ms-data-grid 0.0.59 → 0.0.61
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.
- package/esm2022/lib/data-grid/data-grid.component.mjs +5213 -0
- package/esm2022/lib/data-grid/statuses.mjs +45 -0
- package/esm2022/lib/data-grid.module.mjs +27 -0
- package/esm2022/lib/directives/cell-render-init.directive.mjs +67 -0
- package/esm2022/lib/directives/cellHost.directive.mjs +16 -0
- package/esm2022/lib/pipes/filter.pipe.mjs +28 -0
- package/esm2022/lib/services/common.service.mjs +259 -0
- package/esm2022/lib/services/copy-service.service.mjs +222 -0
- package/esm2022/lib/services/export.service.mjs +149 -0
- package/esm2022/lib/services/split-columns.service.mjs +143 -0
- package/esm2022/ms-data-grid.mjs +5 -0
- package/esm2022/public-api.mjs +6 -0
- package/fesm2022/ms-data-grid.mjs +6150 -0
- package/fesm2022/ms-data-grid.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/data-grid/data-grid.component.d.ts +570 -0
- package/lib/data-grid/statuses.d.ts +3 -0
- package/lib/data-grid.module.d.ts +15 -0
- package/lib/directives/cell-render-init.directive.d.ts +18 -0
- package/lib/directives/cellHost.directive.d.ts +8 -0
- package/lib/pipes/filter.pipe.d.ts +7 -0
- package/lib/services/common.service.d.ts +18 -0
- package/lib/services/copy-service.service.d.ts +14 -0
- package/lib/services/export.service.d.ts +24 -0
- package/lib/services/split-columns.service.d.ts +9 -0
- package/package.json +51 -38
- package/{src/public-api.ts → public-api.d.ts} +2 -6
- package/ng-package.json +0 -18
- package/src/lib/css/bootstrap.css +0 -12043
- package/src/lib/data-grid/animations.ts +0 -267
- package/src/lib/data-grid/data-grid.component.html +0 -5724
- package/src/lib/data-grid/data-grid.component.scss +0 -2126
- package/src/lib/data-grid/data-grid.component.spec.ts +0 -28
- package/src/lib/data-grid/data-grid.component.ts +0 -5780
- package/src/lib/data-grid/statuses.ts +0 -49
- package/src/lib/data-grid.module.ts +0 -21
- package/src/lib/data-grid.service.spec.ts +0 -16
- package/src/lib/data-grid.service.ts +0 -9
- package/src/lib/directives/cell-render-init.directive.spec.ts +0 -11
- package/src/lib/directives/cell-render-init.directive.ts +0 -65
- package/src/lib/directives/cellHost.directive.spec.ts +0 -11
- package/src/lib/directives/cellHost.directive.ts +0 -10
- package/src/lib/directives/draggable-header.directive.spec.ts +0 -11
- package/src/lib/directives/draggable-header.directive.ts +0 -172
- package/src/lib/pipes/filter.pipe.spec.ts +0 -11
- package/src/lib/pipes/filter.pipe.ts +0 -22
- package/src/lib/services/cell-selection.service.spec.ts +0 -16
- package/src/lib/services/cell-selection.service.ts +0 -205
- package/src/lib/services/common.service.spec.ts +0 -16
- package/src/lib/services/common.service.ts +0 -306
- package/src/lib/services/copy-service.service.spec.ts +0 -16
- package/src/lib/services/copy-service.service.ts +0 -252
- package/src/lib/services/drag-drp.service.spec.ts +0 -16
- package/src/lib/services/drag-drp.service.ts +0 -58
- package/src/lib/services/export.service.spec.ts +0 -16
- package/src/lib/services/export.service.ts +0 -189
- package/src/lib/services/split-columns.service.spec.ts +0 -16
- package/src/lib/services/split-columns.service.ts +0 -148
- package/src/lib/services/swap-columns.service.spec.ts +0 -16
- package/src/lib/services/swap-columns.service.ts +0 -162
- package/src/typings.d.ts +0 -4
- package/tsconfig.lib.json +0 -19
- package/tsconfig.lib.prod.json +0 -10
- package/tsconfig.spec.json +0 -14
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
import { Injectable } from '@angular/core';
|
|
2
|
-
import * as XLSX from 'xlsx-js-style';
|
|
3
|
-
import { saveAs } from 'file-saver';
|
|
4
|
-
|
|
5
|
-
@Injectable({
|
|
6
|
-
providedIn: 'root'
|
|
7
|
-
})
|
|
8
|
-
export class ExportService {
|
|
9
|
-
|
|
10
|
-
constructor() {}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Exports data to CSV or Excel.
|
|
14
|
-
* @param columns List of column definitions (each having name/key/is_visible)
|
|
15
|
-
* @param data The array of data objects
|
|
16
|
-
* @param fileName Name of the exported file (without extension)
|
|
17
|
-
* @param format 'csv' | 'xlsx'
|
|
18
|
-
*/
|
|
19
|
-
exportData(
|
|
20
|
-
columns: any[],
|
|
21
|
-
data: any[],
|
|
22
|
-
fileName: string,
|
|
23
|
-
format: 'csv' | 'xlsx' = 'xlsx',
|
|
24
|
-
rowSelectedIndexes: Set<number> | null = new Set(),
|
|
25
|
-
styleConfig: {
|
|
26
|
-
headerBgColor?: string;
|
|
27
|
-
headerTextColor?: string;
|
|
28
|
-
bodyTextColor?: string;
|
|
29
|
-
fontFamily?: string;
|
|
30
|
-
fontWeight?: 'normal' | 'bold';
|
|
31
|
-
zoomScale?: number;
|
|
32
|
-
headerRowHeight?: number;
|
|
33
|
-
selectedRowBgColor?: string;
|
|
34
|
-
} = {}
|
|
35
|
-
) {
|
|
36
|
-
const {
|
|
37
|
-
headerBgColor = '#228B22',
|
|
38
|
-
headerTextColor = '#FFFFFF',
|
|
39
|
-
bodyTextColor = '#000000',
|
|
40
|
-
fontFamily = 'Calibri',
|
|
41
|
-
fontWeight = 'normal',
|
|
42
|
-
zoomScale = 120,
|
|
43
|
-
headerRowHeight = 20,
|
|
44
|
-
selectedRowBgColor = '#8AC5FF',
|
|
45
|
-
} = styleConfig;
|
|
46
|
-
|
|
47
|
-
const visibleColumns = columns.filter(
|
|
48
|
-
col => col.is_visible && col.type !== 'image' && col.type !== 'logo'
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
const headers = visibleColumns.map(col => col.header || col.headerName || col.name);
|
|
52
|
-
|
|
53
|
-
const flattenValue = (value: any): any => {
|
|
54
|
-
if (value == null) return '';
|
|
55
|
-
if (Array.isArray(value))
|
|
56
|
-
return value.map(v => (typeof v === 'object' ? flattenValue(v) : v)).join(', ');
|
|
57
|
-
if (typeof value === 'object')
|
|
58
|
-
return Object.entries(value)
|
|
59
|
-
.map(([k, v]) => `${k}: ${flattenValue(v)}`)
|
|
60
|
-
.join(', ');
|
|
61
|
-
return value;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const exportData = data.map(row =>
|
|
65
|
-
visibleColumns.reduce((acc: any, col) => {
|
|
66
|
-
const header = col.headerName || col.name || col.header;
|
|
67
|
-
let value = this.getNestedValue(row, col.field);
|
|
68
|
-
|
|
69
|
-
switch (col.type) {
|
|
70
|
-
case 'boolean':
|
|
71
|
-
value = value ? 'Yes' : 'No';
|
|
72
|
-
break;
|
|
73
|
-
case 'date':
|
|
74
|
-
if (value) {
|
|
75
|
-
const date = new Date(value);
|
|
76
|
-
if (!isNaN(date.getTime())) {
|
|
77
|
-
value = date.toLocaleDateString('en-US', {
|
|
78
|
-
day: '2-digit',
|
|
79
|
-
month: 'long',
|
|
80
|
-
year: 'numeric',
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
break;
|
|
85
|
-
default:
|
|
86
|
-
value = flattenValue(value);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
acc[header] = value;
|
|
90
|
-
return acc;
|
|
91
|
-
}, {})
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(exportData, { header: headers });
|
|
95
|
-
|
|
96
|
-
// ✅ Define a reusable border style
|
|
97
|
-
const borderStyle = {
|
|
98
|
-
top: { style: 'thin', color: { rgb: 'CCCCCC' } },
|
|
99
|
-
bottom: { style: 'thin', color: { rgb: 'CCCCCC' } },
|
|
100
|
-
left: { style: 'thin', color: { rgb: 'CCCCCC' } },
|
|
101
|
-
right: { style: 'thin', color: { rgb: 'CCCCCC' } },
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
// ✅ Apply header styles
|
|
105
|
-
headers.forEach((header, index) => {
|
|
106
|
-
const cellAddress = XLSX.utils.encode_cell({ r: 0, c: index });
|
|
107
|
-
if (!worksheet[cellAddress]) return;
|
|
108
|
-
|
|
109
|
-
worksheet[cellAddress].s = {
|
|
110
|
-
fill: { fgColor: { rgb: headerBgColor.replace('#', '') } },
|
|
111
|
-
font: {
|
|
112
|
-
name: fontFamily,
|
|
113
|
-
sz: 14,
|
|
114
|
-
color: { rgb: headerTextColor.replace('#', '') },
|
|
115
|
-
bold: fontWeight === 'bold',
|
|
116
|
-
},
|
|
117
|
-
alignment: { horizontal: 'center', vertical: 'center' },
|
|
118
|
-
border: borderStyle, // ✅ Added border here
|
|
119
|
-
};
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
// ✅ Apply body styles + highlight selected rows
|
|
123
|
-
for (let r = 1; r <= exportData.length; r++) {
|
|
124
|
-
const isSelected = rowSelectedIndexes?.has(r - 1);
|
|
125
|
-
const rowBgColor = isSelected ? selectedRowBgColor : '#FFFFFF';
|
|
126
|
-
|
|
127
|
-
for (let c = 0; c < headers.length; c++) {
|
|
128
|
-
const col = visibleColumns[c];
|
|
129
|
-
const cellAddress = XLSX.utils.encode_cell({ r, c });
|
|
130
|
-
const cell = worksheet[cellAddress];
|
|
131
|
-
if (!cell) continue;
|
|
132
|
-
|
|
133
|
-
let horizontalAlign = 'left';
|
|
134
|
-
if (['number', 'boolean', 'date'].includes(col.type)) horizontalAlign = 'center';
|
|
135
|
-
|
|
136
|
-
cell.s = {
|
|
137
|
-
fill: { fgColor: { rgb: rowBgColor.replace('#', '') } },
|
|
138
|
-
font: {
|
|
139
|
-
name: fontFamily,
|
|
140
|
-
sz: 14,
|
|
141
|
-
color: { rgb: bodyTextColor.replace('#', '') },
|
|
142
|
-
bold: false,
|
|
143
|
-
},
|
|
144
|
-
alignment: { horizontal: horizontalAlign, vertical: 'center', wrapText: true },
|
|
145
|
-
border: borderStyle, // ✅ Added border here too
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// ✅ Adjust column widths
|
|
151
|
-
const colWidths = headers.map(header => {
|
|
152
|
-
let maxLength = header.length;
|
|
153
|
-
exportData.forEach(row => {
|
|
154
|
-
const val = row[header];
|
|
155
|
-
if (val != null) {
|
|
156
|
-
const len = val.toString().length;
|
|
157
|
-
if (len > maxLength) maxLength = len;
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
return { wch: Math.min(maxLength + 2, 64) };
|
|
161
|
-
});
|
|
162
|
-
worksheet['!cols'] = colWidths;
|
|
163
|
-
|
|
164
|
-
worksheet['!rows'] = [{ hpt: headerRowHeight }];
|
|
165
|
-
worksheet['!zoom'] = zoomScale;
|
|
166
|
-
|
|
167
|
-
const workbook: XLSX.WorkBook = { Sheets: { Data: worksheet }, SheetNames: ['Data'] };
|
|
168
|
-
|
|
169
|
-
if (format === 'csv') {
|
|
170
|
-
const csv = XLSX.utils.sheet_to_csv(worksheet);
|
|
171
|
-
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
|
|
172
|
-
saveAs(blob, `${fileName}.csv`);
|
|
173
|
-
} else {
|
|
174
|
-
const excelBuffer: any = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
|
|
175
|
-
const blob = new Blob([excelBuffer], {
|
|
176
|
-
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8',
|
|
177
|
-
});
|
|
178
|
-
saveAs(blob, `${fileName}.xlsx`);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
private getNestedValue(obj: any, path: string): any {
|
|
186
|
-
if (!path || typeof obj !== 'object') return obj;
|
|
187
|
-
return path.split('.').reduce((acc, key) => (acc && acc[key] !== undefined ? acc[key] : ''), obj);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/* tslint:disable:no-unused-variable */
|
|
2
|
-
|
|
3
|
-
import { TestBed, async, inject } from '@angular/core/testing';
|
|
4
|
-
import { SplitColumnsService } from './split-columns.service';
|
|
5
|
-
|
|
6
|
-
describe('Service: SplitColumns', () => {
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
TestBed.configureTestingModule({
|
|
9
|
-
providers: [SplitColumnsService]
|
|
10
|
-
});
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('should ...', inject([SplitColumnsService], (service: SplitColumnsService) => {
|
|
14
|
-
expect(service).toBeTruthy();
|
|
15
|
-
}));
|
|
16
|
-
});
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { Injectable } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
@Injectable({
|
|
4
|
-
providedIn: 'root',
|
|
5
|
-
})
|
|
6
|
-
export class SplitColumnsService {
|
|
7
|
-
prepareColumns(columns: any[], containerWidth: number): any {
|
|
8
|
-
const left: any[] = [];
|
|
9
|
-
const center: any[] = [];
|
|
10
|
-
const right: any[] = [];
|
|
11
|
-
|
|
12
|
-
for (const col of columns) {
|
|
13
|
-
if (col.children?.length) {
|
|
14
|
-
const leftChildren: any[] = [];
|
|
15
|
-
const centerChildren: any[] = [];
|
|
16
|
-
const rightChildren: any[] = [];
|
|
17
|
-
|
|
18
|
-
for (const child of col.children) {
|
|
19
|
-
if (child.is_visible === false) continue;
|
|
20
|
-
|
|
21
|
-
const pinned = child.pinned ?? col.pinned ?? null;
|
|
22
|
-
const childWithPinned = { ...child, pinned };
|
|
23
|
-
|
|
24
|
-
if (pinned === 'left') leftChildren.push(childWithPinned);
|
|
25
|
-
else if (pinned === 'right') rightChildren.push(childWithPinned);
|
|
26
|
-
else centerChildren.push(childWithPinned);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (leftChildren.length) {
|
|
30
|
-
left.push({ header: col.header, children: leftChildren, id: col?.id || col?._id });
|
|
31
|
-
}
|
|
32
|
-
if (centerChildren.length) {
|
|
33
|
-
center.push({
|
|
34
|
-
header: col.header,
|
|
35
|
-
children: centerChildren,
|
|
36
|
-
id: col.id || col._id,
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
if (rightChildren.length) {
|
|
40
|
-
right.push({
|
|
41
|
-
header: col.header,
|
|
42
|
-
children: rightChildren,
|
|
43
|
-
id: col.id || col._id,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
} else if (col.is_visible !== false) {
|
|
47
|
-
const pinned = col.pinned ?? null;
|
|
48
|
-
if (pinned === 'left') left.push(col);
|
|
49
|
-
else if (pinned === 'right') right.push(col);
|
|
50
|
-
else center.push(col);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return { left, center, right };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
setColumnsQuery(columns: any[]) {
|
|
58
|
-
for (const col of columns) {
|
|
59
|
-
// if (col.children?.length) {
|
|
60
|
-
// for (const child of col.children) {
|
|
61
|
-
// if (!child?.query?.firt_value && !child?.query?._ids?.length) {
|
|
62
|
-
// child['query'] = {
|
|
63
|
-
// first_condition: 'contain',
|
|
64
|
-
// first_value: null,
|
|
65
|
-
// condition: 'none',
|
|
66
|
-
// second_condition: 'contain',
|
|
67
|
-
// second_value: null,
|
|
68
|
-
// _ids: [],
|
|
69
|
-
// };
|
|
70
|
-
// }
|
|
71
|
-
// }
|
|
72
|
-
// }
|
|
73
|
-
// if (!col?.query?.firt_value && !col?.query?._ids?.length) {
|
|
74
|
-
// col.query = {
|
|
75
|
-
// first_condition: 'contain',
|
|
76
|
-
// first_value: null,
|
|
77
|
-
// condition: 'none',
|
|
78
|
-
// second_condition: 'contain',
|
|
79
|
-
// second_value: null,
|
|
80
|
-
// _ids: [],
|
|
81
|
-
// };
|
|
82
|
-
// }
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
console.log('Updated Columns: ', columns);
|
|
86
|
-
|
|
87
|
-
return columns;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
assignDefaultWidths(columns: any[], containerWidth: number): any[] {
|
|
91
|
-
const visibleLeafCols = this.getVisibleLeafColumns(columns);
|
|
92
|
-
|
|
93
|
-
if (!visibleLeafCols.length) return columns;
|
|
94
|
-
|
|
95
|
-
let defaultWidth = Math.floor(containerWidth / visibleLeafCols.length);
|
|
96
|
-
if (defaultWidth < 150) defaultWidth = 150;
|
|
97
|
-
|
|
98
|
-
const cloneColumns = (cols: any[]): any[] =>
|
|
99
|
-
cols.map((col) => {
|
|
100
|
-
if (col.children?.length) {
|
|
101
|
-
const newChildren = col.children.map((child: any) => {
|
|
102
|
-
// If visible → dynamic default width
|
|
103
|
-
// If invisible → fixed 150px
|
|
104
|
-
if (!child.width) {
|
|
105
|
-
if (child.is_visible === false) {
|
|
106
|
-
return { ...child, width: 150 };
|
|
107
|
-
} else {
|
|
108
|
-
return { ...child, width: defaultWidth };
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return { ...child };
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
return { ...col, children: newChildren };
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (!col.width) {
|
|
118
|
-
if (col.is_visible === false) {
|
|
119
|
-
return { ...col, width: 150 };
|
|
120
|
-
} else {
|
|
121
|
-
return { ...col, width: defaultWidth };
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return { ...col };
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
return cloneColumns(columns);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
private getVisibleLeafColumns(columns: any[]): any[] {
|
|
133
|
-
const result: any[] = [];
|
|
134
|
-
|
|
135
|
-
for (const col of columns) {
|
|
136
|
-
if (col.children?.length) {
|
|
137
|
-
const visibleChildren = col.children.filter(
|
|
138
|
-
(c: any) => c.is_visible !== false
|
|
139
|
-
);
|
|
140
|
-
result.push(...visibleChildren);
|
|
141
|
-
} else if (col.is_visible !== false) {
|
|
142
|
-
result.push(col);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return result;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/* tslint:disable:no-unused-variable */
|
|
2
|
-
|
|
3
|
-
import { TestBed, async, inject } from '@angular/core/testing';
|
|
4
|
-
import { SwapColumnsService } from './swap-columns.service';
|
|
5
|
-
|
|
6
|
-
describe('Service: SwapColumns', () => {
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
TestBed.configureTestingModule({
|
|
9
|
-
providers: [SwapColumnsService]
|
|
10
|
-
});
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('should ...', inject([SwapColumnsService], (service: SwapColumnsService) => {
|
|
14
|
-
expect(service).toBeTruthy();
|
|
15
|
-
}));
|
|
16
|
-
});
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { Injectable } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
@Injectable({
|
|
4
|
-
providedIn: 'root',
|
|
5
|
-
})
|
|
6
|
-
export class SwapColumnsService {
|
|
7
|
-
constructor() {}
|
|
8
|
-
|
|
9
|
-
deepClone(obj: any) {
|
|
10
|
-
return JSON.parse(JSON.stringify(obj));
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
flattenColumnsWithPaths(columns: any[]): { col: any; path: number[] }[] {
|
|
14
|
-
const result: { col: any; path: number[] }[] = [];
|
|
15
|
-
|
|
16
|
-
const recurse = (cols: any[], currentPath: number[] = []) => {
|
|
17
|
-
cols.forEach((col, index) => {
|
|
18
|
-
const path = [...currentPath, index];
|
|
19
|
-
result.push({ col, path });
|
|
20
|
-
|
|
21
|
-
if (Array.isArray(col.children)) {
|
|
22
|
-
recurse(col.children, path);
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
recurse(columns);
|
|
28
|
-
return result;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
findColumnByIndex(
|
|
32
|
-
columns: any[],
|
|
33
|
-
index: number,
|
|
34
|
-
flat: any[],
|
|
35
|
-
_path: number[][] = [],
|
|
36
|
-
currentPath: number[] = []
|
|
37
|
-
): { column: any; parent: any[]; path: number[] } | null {
|
|
38
|
-
for (let i = 0; i < columns.length; i++) {
|
|
39
|
-
const col = columns[i];
|
|
40
|
-
const nextPath = [...currentPath, i];
|
|
41
|
-
|
|
42
|
-
if (flat[index] === col) {
|
|
43
|
-
return { column: col, parent: columns, path: nextPath };
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (Array.isArray(col?.children)) {
|
|
47
|
-
const result = this.findColumnByIndex(
|
|
48
|
-
col?.children,
|
|
49
|
-
index,
|
|
50
|
-
flat,
|
|
51
|
-
_path,
|
|
52
|
-
nextPath
|
|
53
|
-
);
|
|
54
|
-
if (result) return result;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
insertAtPath(columns: any[], path: number[], newColumn: any): any[] {
|
|
62
|
-
const cloned = this.deepClone(columns);
|
|
63
|
-
let current = cloned;
|
|
64
|
-
|
|
65
|
-
for (let i = 0; i < path.length - 1; i++) {
|
|
66
|
-
if (!current[path[i]]?.children) {
|
|
67
|
-
current[path[i]]!.children = [];
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
current = current[path[i]]?.children;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const insertIndex = path[path.length - 1];
|
|
74
|
-
current.splice(insertIndex, 0, newColumn);
|
|
75
|
-
return cloned;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
removeAtPath(columns: any[], path: number[]): any[] {
|
|
79
|
-
const cloned = this.deepClone(columns);
|
|
80
|
-
let current = cloned;
|
|
81
|
-
|
|
82
|
-
for (let i = 0; i < path.length - 1; i++) {
|
|
83
|
-
if (!current[path[i]]?.children) {
|
|
84
|
-
return cloned; // Safety: path is invalid
|
|
85
|
-
}
|
|
86
|
-
current = current[path[i]]?.children;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const removeIndex = path[path.length - 1];
|
|
90
|
-
if (Array.isArray(current) && current.length > removeIndex) {
|
|
91
|
-
current.splice(removeIndex, 1);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return cloned;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
swapColumnsInTree(
|
|
98
|
-
currentColumn: any,
|
|
99
|
-
columns: any[],
|
|
100
|
-
fromIndex: number,
|
|
101
|
-
toIndex: number
|
|
102
|
-
): any[] {
|
|
103
|
-
const flat = this.flattenColumnsWithPaths(columns);
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
fromIndex < 0 ||
|
|
107
|
-
toIndex < 0 ||
|
|
108
|
-
fromIndex >= flat.length ||
|
|
109
|
-
toIndex >= flat.length
|
|
110
|
-
) {
|
|
111
|
-
return columns; // invalid indices
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const fromInfo = this.findColumnByIndex(columns, fromIndex, flat);
|
|
115
|
-
const toInfo = this.findColumnByIndex(columns, toIndex, flat);
|
|
116
|
-
|
|
117
|
-
if (!fromInfo || !toInfo) return columns;
|
|
118
|
-
|
|
119
|
-
const fromCol = fromInfo.column;
|
|
120
|
-
const toCol = toInfo.column;
|
|
121
|
-
|
|
122
|
-
let updatedCols = this.removeAtPath(columns, fromInfo.path);
|
|
123
|
-
|
|
124
|
-
// Case 1: Same parent
|
|
125
|
-
if (
|
|
126
|
-
JSON.stringify(fromInfo.path.slice(0, -1)) ===
|
|
127
|
-
JSON.stringify(toInfo.path.slice(0, -1))
|
|
128
|
-
) {
|
|
129
|
-
return this.insertAtPath(updatedCols, toInfo.path, fromCol);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Case 2: Drop target is a group header
|
|
133
|
-
if (Array.isArray(toCol?.children)) {
|
|
134
|
-
const cloned = this.deepClone(updatedCols);
|
|
135
|
-
let parent = cloned;
|
|
136
|
-
|
|
137
|
-
for (let i = 0; i < toInfo.path.length - 1; i++) {
|
|
138
|
-
parent = parent[toInfo.path[i]].children;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const target = parent[toInfo.path[toInfo.path.length - 1]];
|
|
142
|
-
if (!target.children) {
|
|
143
|
-
target.children = [];
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
target.children.push(fromCol);
|
|
147
|
-
return cloned;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Case 3: Drop target is a regular column → wrap both into a group
|
|
151
|
-
const groupHeader = {
|
|
152
|
-
headerName: toCol.headerName || 'Group',
|
|
153
|
-
children: [toCol, fromCol],
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
// Remove target from its original location
|
|
157
|
-
updatedCols = this.removeAtPath(updatedCols, toInfo.path);
|
|
158
|
-
|
|
159
|
-
// Insert group at target index
|
|
160
|
-
return this.insertAtPath(updatedCols, toInfo.path, groupHeader);
|
|
161
|
-
}
|
|
162
|
-
}
|
package/src/typings.d.ts
DELETED
package/tsconfig.lib.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"outDir": "../../out-tsc/lib",
|
|
5
|
-
"declaration": true,
|
|
6
|
-
"declarationMap": true,
|
|
7
|
-
"inlineSources": true,
|
|
8
|
-
"types": [],
|
|
9
|
-
"target": "es2019",
|
|
10
|
-
"lib": ["es2019", "dom"]
|
|
11
|
-
},
|
|
12
|
-
"exclude": [
|
|
13
|
-
"**/*.spec.ts"
|
|
14
|
-
],
|
|
15
|
-
"include": [
|
|
16
|
-
"src/**/*.ts",
|
|
17
|
-
"src/typings.d.ts"
|
|
18
|
-
]
|
|
19
|
-
}
|
package/tsconfig.lib.prod.json
DELETED
package/tsconfig.spec.json
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
|
2
|
-
{
|
|
3
|
-
"extends": "../../tsconfig.json",
|
|
4
|
-
"compilerOptions": {
|
|
5
|
-
"outDir": "../../out-tsc/spec",
|
|
6
|
-
"types": [
|
|
7
|
-
"jasmine"
|
|
8
|
-
]
|
|
9
|
-
},
|
|
10
|
-
"include": [
|
|
11
|
-
"**/*.spec.ts",
|
|
12
|
-
"**/*.d.ts"
|
|
13
|
-
]
|
|
14
|
-
}
|