@syncfusion/ej2-treegrid 30.2.4 → 31.1.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.
- package/dist/ej2-treegrid.min.js +2 -2
- package/dist/ej2-treegrid.umd.min.js +2 -2
- package/dist/ej2-treegrid.umd.min.js.map +1 -1
- package/dist/es6/ej2-treegrid.es2015.js +263 -157
- package/dist/es6/ej2-treegrid.es2015.js.map +1 -1
- package/dist/es6/ej2-treegrid.es5.js +291 -167
- package/dist/es6/ej2-treegrid.es5.js.map +1 -1
- package/dist/global/ej2-treegrid.min.js +2 -2
- package/dist/global/ej2-treegrid.min.js.map +1 -1
- package/dist/global/index.d.ts +1 -1
- package/dist/ts/index.d.ts +4 -0
- package/dist/ts/index.ts +4 -0
- package/dist/ts/treegrid/actions/batch-edit.d.ts +74 -0
- package/dist/ts/treegrid/actions/batch-edit.ts +627 -0
- package/dist/ts/treegrid/actions/clipboard.d.ts +36 -0
- package/dist/ts/treegrid/actions/clipboard.ts +174 -0
- package/dist/ts/treegrid/actions/column-chooser.d.ts +37 -0
- package/dist/ts/treegrid/actions/column-chooser.ts +55 -0
- package/dist/ts/treegrid/actions/column-menu.d.ts +24 -0
- package/dist/ts/treegrid/actions/column-menu.ts +39 -0
- package/dist/ts/treegrid/actions/command-column.d.ts +24 -0
- package/dist/ts/treegrid/actions/command-column.ts +32 -0
- package/dist/ts/treegrid/actions/context-menu.d.ts +42 -0
- package/dist/ts/treegrid/actions/context-menu.ts +149 -0
- package/dist/ts/treegrid/actions/crud-actions.d.ts +66 -0
- package/dist/ts/treegrid/actions/crud-actions.ts +388 -0
- package/dist/ts/treegrid/actions/detail-row.d.ts +39 -0
- package/dist/ts/treegrid/actions/detail-row.ts +124 -0
- package/dist/ts/treegrid/actions/edit.d.ts +121 -0
- package/dist/ts/treegrid/actions/edit.ts +1083 -0
- package/dist/ts/treegrid/actions/excel-export.d.ts +67 -0
- package/dist/ts/treegrid/actions/excel-export.ts +240 -0
- package/dist/ts/treegrid/actions/filter.d.ts +57 -0
- package/dist/ts/treegrid/actions/filter.ts +231 -0
- package/dist/ts/treegrid/actions/freeze-column.d.ts +28 -0
- package/dist/ts/treegrid/actions/freeze-column.ts +119 -0
- package/dist/ts/treegrid/actions/index.d.ts +24 -0
- package/dist/ts/treegrid/actions/index.ts +24 -0
- package/dist/ts/treegrid/actions/infinite-scroll.d.ts +96 -0
- package/dist/ts/treegrid/actions/infinite-scroll.ts +320 -0
- package/dist/ts/treegrid/actions/logger.d.ts +25 -0
- package/dist/ts/treegrid/actions/logger.ts +136 -0
- package/dist/ts/treegrid/actions/page.d.ts +67 -0
- package/dist/ts/treegrid/actions/page.ts +212 -0
- package/dist/ts/treegrid/actions/pdf-export.d.ts +63 -0
- package/dist/ts/treegrid/actions/pdf-export.ts +182 -0
- package/dist/ts/treegrid/actions/print.d.ts +37 -0
- package/dist/ts/treegrid/actions/print.ts +69 -0
- package/dist/ts/treegrid/actions/reorder.d.ts +36 -0
- package/dist/ts/treegrid/actions/reorder.ts +60 -0
- package/dist/ts/treegrid/actions/resize.d.ts +36 -0
- package/dist/ts/treegrid/actions/resize.ts +54 -0
- package/dist/ts/treegrid/actions/rowdragdrop.d.ts +405 -0
- package/dist/ts/treegrid/actions/rowdragdrop.ts +1896 -0
- package/dist/ts/treegrid/actions/selection.d.ts +51 -0
- package/dist/ts/treegrid/actions/selection.ts +530 -0
- package/dist/ts/treegrid/actions/sort.d.ts +63 -0
- package/dist/ts/treegrid/actions/sort.ts +149 -0
- package/dist/ts/treegrid/actions/summary.d.ts +47 -0
- package/dist/ts/treegrid/actions/summary.ts +231 -0
- package/dist/ts/treegrid/actions/toolbar.d.ts +52 -0
- package/dist/ts/treegrid/actions/toolbar.ts +154 -0
- package/dist/ts/treegrid/actions/virtual-scroll.d.ts +90 -0
- package/dist/ts/treegrid/actions/virtual-scroll.ts +306 -0
- package/dist/ts/treegrid/base/constant.d.ts +158 -0
- package/dist/ts/treegrid/base/constant.ts +158 -0
- package/dist/ts/treegrid/base/data.d.ts +90 -0
- package/dist/ts/treegrid/base/data.ts +904 -0
- package/dist/ts/treegrid/base/index.d.ts +11 -0
- package/dist/ts/treegrid/base/index.ts +11 -0
- package/dist/ts/treegrid/base/interface.d.ts +186 -0
- package/dist/ts/treegrid/base/interface.ts +191 -0
- package/dist/ts/treegrid/base/treegrid-model.d.ts +1100 -0
- package/dist/ts/treegrid/base/treegrid.d.ts +2422 -0
- package/dist/ts/treegrid/base/treegrid.ts +5962 -0
- package/dist/ts/treegrid/enum.d.ts +152 -0
- package/dist/ts/treegrid/enum.ts +217 -0
- package/dist/ts/treegrid/index.d.ts +9 -0
- package/dist/ts/treegrid/index.ts +9 -0
- package/dist/ts/treegrid/models/column-chooser-settings-model.d.ts +62 -0
- package/dist/ts/treegrid/models/column-chooser-settings.d.ts +53 -0
- package/dist/ts/treegrid/models/column-chooser-settings.ts +67 -0
- package/dist/ts/treegrid/models/column-model.d.ts +30 -0
- package/dist/ts/treegrid/models/column.d.ts +697 -0
- package/dist/ts/treegrid/models/column.ts +800 -0
- package/dist/ts/treegrid/models/edit-settings-model.d.ts +100 -0
- package/dist/ts/treegrid/models/edit-settings.d.ts +89 -0
- package/dist/ts/treegrid/models/edit-settings.ts +111 -0
- package/dist/ts/treegrid/models/filter-settings-model.d.ts +216 -0
- package/dist/ts/treegrid/models/filter-settings.d.ts +195 -0
- package/dist/ts/treegrid/models/filter-settings.ts +237 -0
- package/dist/ts/treegrid/models/index.d.ts +24 -0
- package/dist/ts/treegrid/models/index.ts +24 -0
- package/dist/ts/treegrid/models/infinite-scroll-settings-model.d.ts +29 -0
- package/dist/ts/treegrid/models/infinite-scroll-settings.d.ts +25 -0
- package/dist/ts/treegrid/models/infinite-scroll-settings.ts +31 -0
- package/dist/ts/treegrid/models/loading-indicator-model.d.ts +21 -0
- package/dist/ts/treegrid/models/loading-indicator.d.ts +19 -0
- package/dist/ts/treegrid/models/loading-indicator.ts +21 -0
- package/dist/ts/treegrid/models/page-settings-model.d.ts +66 -0
- package/dist/ts/treegrid/models/page-settings.d.ts +57 -0
- package/dist/ts/treegrid/models/page-settings.ts +73 -0
- package/dist/ts/treegrid/models/rowdrop-settings-model.d.ts +15 -0
- package/dist/ts/treegrid/models/rowdrop-settings.d.ts +34 -0
- package/dist/ts/treegrid/models/rowdrop-settings.ts +37 -0
- package/dist/ts/treegrid/models/search-settings-model.d.ts +79 -0
- package/dist/ts/treegrid/models/search-settings.d.ts +73 -0
- package/dist/ts/treegrid/models/search-settings.ts +83 -0
- package/dist/ts/treegrid/models/selection-settings-model.d.ts +76 -0
- package/dist/ts/treegrid/models/selection-settings.d.ts +68 -0
- package/dist/ts/treegrid/models/selection-settings.ts +82 -0
- package/dist/ts/treegrid/models/sort-settings-model.d.ts +49 -0
- package/dist/ts/treegrid/models/sort-settings.d.ts +43 -0
- package/dist/ts/treegrid/models/sort-settings.ts +51 -0
- package/dist/ts/treegrid/models/summary-model.d.ts +93 -0
- package/dist/ts/treegrid/models/summary.d.ts +126 -0
- package/dist/ts/treegrid/models/summary.ts +170 -0
- package/dist/ts/treegrid/models/textwrap-settings-model.d.ts +21 -0
- package/dist/ts/treegrid/models/textwrap-settings.d.ts +19 -0
- package/dist/ts/treegrid/models/textwrap-settings.ts +21 -0
- package/dist/ts/treegrid/renderer/index.d.ts +5 -0
- package/dist/ts/treegrid/renderer/index.ts +5 -0
- package/dist/ts/treegrid/renderer/render.d.ts +41 -0
- package/dist/ts/treegrid/renderer/render.ts +379 -0
- package/dist/ts/treegrid/renderer/virtual-row-model-generator.d.ts +16 -0
- package/dist/ts/treegrid/renderer/virtual-row-model-generator.ts +90 -0
- package/dist/ts/treegrid/renderer/virtual-tree-content-render.d.ts +353 -0
- package/dist/ts/treegrid/renderer/virtual-tree-content-render.ts +1125 -0
- package/dist/ts/treegrid/utils.d.ts +70 -0
- package/dist/ts/treegrid/utils.ts +217 -0
- package/package.json +51 -15
- package/src/treegrid/actions/context-menu.js +3 -1
- package/src/treegrid/actions/excel-export.d.ts +8 -0
- package/src/treegrid/actions/excel-export.js +12 -0
- package/src/treegrid/actions/freeze-column.js +1 -1
- package/src/treegrid/actions/pdf-export.d.ts +8 -0
- package/src/treegrid/actions/pdf-export.js +12 -0
- package/src/treegrid/actions/selection.js +1 -1
- package/src/treegrid/actions/virtual-scroll.js +2 -2
- package/src/treegrid/base/data.js +1 -1
- package/src/treegrid/base/treegrid-model.d.ts +32 -2
- package/src/treegrid/base/treegrid.d.ts +29 -2
- package/src/treegrid/base/treegrid.js +39 -2
- package/src/treegrid/models/column-chooser-settings-model.d.ts +62 -0
- package/src/treegrid/models/column-chooser-settings.d.ts +53 -0
- package/src/treegrid/models/column-chooser-settings.js +52 -0
- package/src/treegrid/renderer/virtual-tree-content-render.js +3 -8
- package/src/treegrid/utils.js +22 -6
|
@@ -0,0 +1,1896 @@
|
|
|
1
|
+
import { TreeGrid } from '../base/treegrid';
|
|
2
|
+
import { Grid, RowDD as GridDragDrop, RowDropEventArgs, parentsUntil, Row, Column } from '@syncfusion/ej2-grids';
|
|
3
|
+
import { EJ2Intance, getObject, Scroll } from '@syncfusion/ej2-grids';
|
|
4
|
+
import { closest, isNullOrUndefined, setValue, extend, getValue, removeClass, addClass, setStyleAttribute } from '@syncfusion/ej2-base';
|
|
5
|
+
import { ITreeData } from '../base';
|
|
6
|
+
import { DataManager } from '@syncfusion/ej2-data';
|
|
7
|
+
import * as events from '../base/constant';
|
|
8
|
+
import { editAction } from './crud-actions';
|
|
9
|
+
import { getParentData, findChildrenRecords, isRemoteData, isOffline, isCountRequired } from '../utils';
|
|
10
|
+
import { TreeActionEventArgs } from '../models';
|
|
11
|
+
import { RowDragEventArgs } from '../base';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* TreeGrid RowDragAndDrop module
|
|
15
|
+
*
|
|
16
|
+
* @hidden
|
|
17
|
+
*/
|
|
18
|
+
export class RowDD {
|
|
19
|
+
private parent: TreeGrid;
|
|
20
|
+
/** @hidden
|
|
21
|
+
* Represents the position where a row can be dropped within the TreeGrid.
|
|
22
|
+
*/
|
|
23
|
+
private dropPosition: string;
|
|
24
|
+
/** @hidden
|
|
25
|
+
* Represents the record that is currently being dragged in the TreeGrid.
|
|
26
|
+
*/
|
|
27
|
+
private draggedRecord: ITreeData;
|
|
28
|
+
/** @hidden
|
|
29
|
+
* Represents the record that the currently dragged item is being dropped onto in the TreeGrid.
|
|
30
|
+
*/
|
|
31
|
+
private droppedRecord: ITreeData;
|
|
32
|
+
/** @hidden
|
|
33
|
+
* Stores the data representation of the TreeGrid, including hierarchical structures.
|
|
34
|
+
*/
|
|
35
|
+
public treeGridData: ITreeData[];
|
|
36
|
+
/** @hidden
|
|
37
|
+
* Represents the underlying hierarchical data of the TreeGrid.
|
|
38
|
+
*/
|
|
39
|
+
private treeData: ITreeData[];
|
|
40
|
+
/** @hidden
|
|
41
|
+
* Indicates whether a row can be dropped into the current target position during a drag-and-drop operation.
|
|
42
|
+
*/
|
|
43
|
+
private canDrop: boolean = true;
|
|
44
|
+
/** @hidden
|
|
45
|
+
* Indicates whether the current drag operation includes child records of the dragged item.
|
|
46
|
+
*/
|
|
47
|
+
private isDraggedWithChild: boolean = false;
|
|
48
|
+
/** @hidden
|
|
49
|
+
*
|
|
50
|
+
*/
|
|
51
|
+
public isMultipleGrid: string;
|
|
52
|
+
/** @hidden
|
|
53
|
+
* Indicates whether multiple TreeGrid instances are being managed or displayed.
|
|
54
|
+
*/
|
|
55
|
+
private modifiedRecords: string = 'modifiedRecords';
|
|
56
|
+
/** @hidden
|
|
57
|
+
* Represents the currently selected item in the TreeGrid.
|
|
58
|
+
*/
|
|
59
|
+
private selectedItem: ITreeData;
|
|
60
|
+
/** @hidden
|
|
61
|
+
* Represents the currently selected item in the TreeGrid.
|
|
62
|
+
*/
|
|
63
|
+
private selectedRecords: string = 'selectedRecords';
|
|
64
|
+
/** @hidden
|
|
65
|
+
* Holds an array of currently selected records in the TreeGrid.
|
|
66
|
+
*/
|
|
67
|
+
private selectedRows: string = 'selectedRows';
|
|
68
|
+
/** @hidden
|
|
69
|
+
* Indicates whether there is a droppable item in the TreeGrid.
|
|
70
|
+
*/
|
|
71
|
+
private hasDropItem: boolean = true;
|
|
72
|
+
/** @hidden
|
|
73
|
+
* Indicates whether the item is being added to the bottom of the TreeGrid.
|
|
74
|
+
*/
|
|
75
|
+
public isaddtoBottom: boolean = false;
|
|
76
|
+
private selectedRecord: ITreeData;
|
|
77
|
+
private selectedRow: HTMLTableRowElement;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Constructor for render module
|
|
81
|
+
*
|
|
82
|
+
* @param {TreeGrid} parent - Tree Grid instance
|
|
83
|
+
*/
|
|
84
|
+
constructor(parent?: TreeGrid) {
|
|
85
|
+
Grid.Inject(GridDragDrop);
|
|
86
|
+
this.parent = parent;
|
|
87
|
+
this.addEventListener();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Retrieves child records for a specified parent ID in the TreeGrid.
|
|
92
|
+
*
|
|
93
|
+
* @param {string} id - The unique ID of the parent record for which to retrieve child records.
|
|
94
|
+
* @returns {ITreeData[]} An array of child records corresponding to the specified parent ID.
|
|
95
|
+
*/
|
|
96
|
+
private getChildrecordsByParentID(id: string): ITreeData[] {
|
|
97
|
+
let treeGridDataSource: Object;
|
|
98
|
+
if (this.parent.dataSource instanceof DataManager && isOffline(this.parent)) {
|
|
99
|
+
treeGridDataSource = (<DataManager>this.parent.grid.dataSource).dataSource.json;
|
|
100
|
+
} else {
|
|
101
|
+
treeGridDataSource = this.parent.grid.dataSource;
|
|
102
|
+
}
|
|
103
|
+
const record: Object[] = (treeGridDataSource as ITreeData[]).filter((e: ITreeData) => {
|
|
104
|
+
return e.uniqueID === id;
|
|
105
|
+
});
|
|
106
|
+
return record;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @hidden
|
|
111
|
+
* @returns {void}
|
|
112
|
+
*/
|
|
113
|
+
private addEventListener(): void {
|
|
114
|
+
this.parent.on(events.rowdraging, this.Rowdraging, this);
|
|
115
|
+
this.parent.on(events.rowDropped, this.rowDropped, this);
|
|
116
|
+
this.parent.on(events.rowsAdd, this.rowsAdded, this);
|
|
117
|
+
this.parent.on(events.rowsRemove, this.rowsRemoved, this);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Reorder the rows based on given indexes and position
|
|
122
|
+
*
|
|
123
|
+
* @returns {void}
|
|
124
|
+
* @param {number[]} fromIndexes - source indexes of rows to be re-ordered
|
|
125
|
+
* @param {number} toIndex - Destination row index
|
|
126
|
+
* @param {string} position - Drop position as above or below or child
|
|
127
|
+
*/
|
|
128
|
+
public reorderRows(fromIndexes: number[], toIndex: number, position: string): void {
|
|
129
|
+
const tObj: TreeGrid = this.parent;
|
|
130
|
+
if (fromIndexes[0] === toIndex || ['above', 'below', 'child'].indexOf(position) === -1) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const action: string = 'action'; const dropPosition: string = 'dropPosition';
|
|
134
|
+
if (fromIndexes[0] !== toIndex && ['above', 'below', 'child'].indexOf(position) !== -1) {
|
|
135
|
+
if (position === 'above') {
|
|
136
|
+
this.dropPosition = 'topSegment';
|
|
137
|
+
}
|
|
138
|
+
if (position === 'below') {
|
|
139
|
+
this.dropPosition = 'bottomSegment';
|
|
140
|
+
}
|
|
141
|
+
if (position === 'child') {
|
|
142
|
+
this.dropPosition = 'middleSegment';
|
|
143
|
+
}
|
|
144
|
+
this.parent[`${dropPosition}`] = this.dropPosition;
|
|
145
|
+
const data: ITreeData[] = [];
|
|
146
|
+
for (let i: number = 0; i < fromIndexes.length; i++) {
|
|
147
|
+
const index: number = (this.parent.getRowByIndex(fromIndexes[parseInt(i.toString(), 10)]) as HTMLTableRowElement).rowIndex;
|
|
148
|
+
data[parseInt(i.toString(), 10)] = this.parent.getCurrentViewRecords()[parseInt(index.toString(), 10)];
|
|
149
|
+
}
|
|
150
|
+
const isByMethod: boolean = true;
|
|
151
|
+
const args: RowDropEventArgs = {
|
|
152
|
+
data: data,
|
|
153
|
+
dropIndex: toIndex
|
|
154
|
+
};
|
|
155
|
+
if (!isCountRequired(this.parent)) {
|
|
156
|
+
this.dropRows(args, isByMethod);
|
|
157
|
+
}
|
|
158
|
+
//this.refreshGridDataSource();
|
|
159
|
+
if (tObj.isLocalData) {
|
|
160
|
+
tObj.flatData = this.orderToIndex(tObj.flatData);
|
|
161
|
+
}
|
|
162
|
+
if (this.parent[`${action}`] === 'outdenting') {
|
|
163
|
+
if (!isNullOrUndefined(data[0].parentItem)) {
|
|
164
|
+
data[0].level = data[0].parentItem.level + 1;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
this.parent.grid.refresh();
|
|
168
|
+
if (this.parent.enableImmutableMode && this.dropPosition === 'middleSegment') {
|
|
169
|
+
const index: number = this.parent.allowRowDragAndDrop
|
|
170
|
+
? this.parent.treeColumnIndex + 1
|
|
171
|
+
: (this.parent[`${action}`] === 'indenting' ? this.parent.treeColumnIndex : undefined);
|
|
172
|
+
const row: HTMLTableRowElement = this.parent.getRows()[fromIndexes[0]];
|
|
173
|
+
const dropData: Object = args.data[0];
|
|
174
|
+
const totalRecord: Object[] = []; const rows: HTMLTableRowElement[] = [];
|
|
175
|
+
totalRecord.push(dropData); rows.push(row);
|
|
176
|
+
const parentUniqueID: string = 'parentUniqueID';
|
|
177
|
+
const parentData: Object = getParentData(this.parent, args.data[0][`${parentUniqueID}`]);
|
|
178
|
+
const parentrow: HTMLTableRowElement = this.parent.getRows()[parseInt(toIndex.toString(), 10)];
|
|
179
|
+
totalRecord.push(parentData); rows.push(parentrow);
|
|
180
|
+
this.updateRowAndCellElements(totalRecord, rows, index);
|
|
181
|
+
}
|
|
182
|
+
if (this.parent.enableImmutableMode && this.parent[`${action}`] === 'outdenting') {
|
|
183
|
+
const index: number = this.parent.allowRowDragAndDrop
|
|
184
|
+
? this.parent.treeColumnIndex + 1
|
|
185
|
+
: (this.parent[`${action}`] === 'outdenting' ? this.parent.treeColumnIndex : undefined);
|
|
186
|
+
const record: Object = args.data[0];
|
|
187
|
+
const row: HTMLTableRowElement = this.parent.getRows()[fromIndexes[0]];
|
|
188
|
+
const totalRecord: Object[] = []; const rows: HTMLTableRowElement[] = [];
|
|
189
|
+
totalRecord.push(record); rows.push(row);
|
|
190
|
+
this.updateRowAndCellElements(totalRecord, rows, index);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Updates the rows and cells
|
|
197
|
+
*
|
|
198
|
+
* @param {Object[]} records - Updates the given records
|
|
199
|
+
* @param {HTMLTableRowElement[]} rows - Updates the given rows
|
|
200
|
+
* @param {number} index - Updates the given cell index
|
|
201
|
+
* @returns {void}
|
|
202
|
+
*/
|
|
203
|
+
private updateRowAndCellElements(records: Object[], rows: HTMLTableRowElement[], index: number): void {
|
|
204
|
+
for (let i: number = 0; i < records.length; i++) {
|
|
205
|
+
this.parent.renderModule.cellRender({
|
|
206
|
+
data: records[parseInt(i.toString(), 10)], cell: rows[parseInt(i.toString(), 10)].cells[parseInt(index.toString(), 10)] ,
|
|
207
|
+
column: this.parent.grid.getColumns()[this.parent.treeColumnIndex],
|
|
208
|
+
requestType: 'rowDragAndDrop'
|
|
209
|
+
});
|
|
210
|
+
if (this.parent['action'] === 'indenting' || this.parent['action'] === 'outdenting') {
|
|
211
|
+
this.parent.renderModule.RowModifier({
|
|
212
|
+
data: records[parseInt(i.toString(), 10)], row: rows[parseInt(i.toString(), 10)]
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Performs indent or outdent actions on selected records in the TreeGrid.
|
|
220
|
+
*
|
|
221
|
+
* @param {ITreeData} [record] - The record to be indented or outdented. If undefined, the method operates on the currently selected record.
|
|
222
|
+
* @param {string} [request] - The action to perform, either 'indent' or 'outdent'.
|
|
223
|
+
* @returns {void}
|
|
224
|
+
*/
|
|
225
|
+
private indentOutdentAction(record?: ITreeData, request?: string): void {
|
|
226
|
+
const tObj: TreeGrid = this.parent; const action: string = 'action';
|
|
227
|
+
const droppedIndex: string = 'dropIndex'; let selectedItemIndex: number = -1;
|
|
228
|
+
if (isNullOrUndefined(record) && this.parent.selectedRowIndex === -1) {
|
|
229
|
+
return;
|
|
230
|
+
} else {
|
|
231
|
+
if (this.parent.enableVirtualization && this.parent.selectedRowIndex !== -1) {
|
|
232
|
+
selectedItemIndex = (this.parent.getSelectedRows()[0] as HTMLTableRowElement).rowIndex;
|
|
233
|
+
} else if (this.parent.selectedRowIndex !== -1) {
|
|
234
|
+
selectedItemIndex = this.parent.selectedRowIndex;
|
|
235
|
+
}
|
|
236
|
+
this.selectedItem = isNullOrUndefined(record) ?
|
|
237
|
+
tObj.getCurrentViewRecords()[parseInt(selectedItemIndex.toString(), 10)] as ITreeData : record as ITreeData;
|
|
238
|
+
const primaryKeyField: string = this.parent.getPrimaryKeyFieldNames()[0];
|
|
239
|
+
const rowIndex: number = this.parent.grid.getRowIndexByPrimaryKey(this.selectedItem[`${primaryKeyField}`]);
|
|
240
|
+
this.selectedRow = this.parent[this.selectedRows] = selectedItemIndex !== -1 ?
|
|
241
|
+
this.parent.getSelectedRows()[0] as HTMLTableRowElement
|
|
242
|
+
: this.parent.grid.getRowByIndex(rowIndex) as HTMLTableRowElement;
|
|
243
|
+
this.selectedRecord = this.parent[this.selectedRecords] = selectedItemIndex !== -1 ?
|
|
244
|
+
tObj.getCurrentViewRecords()[parseInt(selectedItemIndex.toString(), 10)] as ITreeData
|
|
245
|
+
: this.selectedItem as ITreeData;
|
|
246
|
+
if (request === 'indent') {
|
|
247
|
+
const record: ITreeData = tObj.getCurrentViewRecords()[this.selectedRow.rowIndex - 1];
|
|
248
|
+
let dropIndex: number;
|
|
249
|
+
if (this.selectedRow.rowIndex === 0 || this.selectedRow.rowIndex === -1 ||
|
|
250
|
+
(tObj.getCurrentViewRecords()[this.selectedRow.rowIndex] as ITreeData).level - record.level === 1) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
if (record.level > this.selectedRecord.level) {
|
|
254
|
+
for (let i: number = 0; i < tObj.getCurrentViewRecords().length; i++) {
|
|
255
|
+
if ((tObj.getCurrentViewRecords()[parseInt(i.toString(), 10)] as ITreeData).taskData ===
|
|
256
|
+
record.parentItem.taskData) {
|
|
257
|
+
dropIndex = i;
|
|
258
|
+
if (tObj.enableVirtualization) {
|
|
259
|
+
dropIndex = parseInt(tObj.getRows()[parseInt(i.toString(), 10)].getAttribute('aria-rowindex'), 10) - 1;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
dropIndex = this.selectedRow.rowIndex - 1;
|
|
266
|
+
}
|
|
267
|
+
if (this.parent.enableVirtualization && this.selectedRecord && !(record.level > this.selectedRecord.level)) {
|
|
268
|
+
dropIndex = parseInt(this.selectedRow.getAttribute('aria-rowindex'), 10) - 2;
|
|
269
|
+
}
|
|
270
|
+
tObj[`${action}`] = 'indenting'; tObj[`${droppedIndex}`] = dropIndex;
|
|
271
|
+
this.eventTrigger('indenting', dropIndex);
|
|
272
|
+
} else if (request === 'outdent') {
|
|
273
|
+
const isInvalidSelection: boolean = this.selectedRow.rowIndex === -1 || this.selectedRow.rowIndex === 0;
|
|
274
|
+
const isRootLevel: boolean = (tObj.getCurrentViewRecords()[this.selectedRow.rowIndex] as ITreeData).level === 0;
|
|
275
|
+
if (isInvalidSelection || isRootLevel) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const parentItem: ITreeData = this.selectedRecord.parentItem;
|
|
279
|
+
const records: object[] = tObj.getCurrentViewRecords();
|
|
280
|
+
let dropIndex: number = records.findIndex((record: ITreeData) => record.uniqueID === parentItem.uniqueID);
|
|
281
|
+
if (dropIndex === -1) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (this.parent.enableVirtualization && this.selectedRecord) {
|
|
285
|
+
const ariaRowIndex: string = this.parent.getRows()[parseInt(dropIndex.toString(), 10)].getAttribute('aria-rowindex');
|
|
286
|
+
dropIndex = parseInt(ariaRowIndex, 10) - 1;
|
|
287
|
+
}
|
|
288
|
+
tObj[`${action}`] = 'outdenting'; tObj[`${droppedIndex}`] = dropIndex;
|
|
289
|
+
this.eventTrigger('outdenting', dropIndex);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Triggers a specified event for the TreeGrid, notifying subscribers about the event occurrence.
|
|
296
|
+
*
|
|
297
|
+
* @param {string} action - The action to be triggered, either 'indenting' or 'outdenting'.
|
|
298
|
+
* @param {number} dropIndex - The index at which the row should be dropped.
|
|
299
|
+
* @returns {void}
|
|
300
|
+
*/
|
|
301
|
+
private eventTrigger(action: string, dropIndex: number): void {
|
|
302
|
+
const actionArgs: TreeActionEventArgs = {
|
|
303
|
+
action: action,
|
|
304
|
+
cancel: false,
|
|
305
|
+
data: [this.parent[this.selectedRecords]],
|
|
306
|
+
row: this.parent[this.selectedRows]
|
|
307
|
+
};
|
|
308
|
+
this.parent.trigger(events.actionBegin, actionArgs, (actionArgs: TreeActionEventArgs) => {
|
|
309
|
+
if (!actionArgs.cancel) {
|
|
310
|
+
if (actionArgs.action === 'indenting') {
|
|
311
|
+
if (this.parent.enableVirtualization) {
|
|
312
|
+
this.reorderRows([parseInt(this.selectedRow.getAttribute('aria-rowindex'), 10) - 1], dropIndex, 'child');
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
this.reorderRows([this.selectedRow.rowIndex], dropIndex, 'child');
|
|
316
|
+
}
|
|
317
|
+
} else if (actionArgs.action === 'outdenting') {
|
|
318
|
+
if (this.parent.enableVirtualization) {
|
|
319
|
+
this.reorderRows([parseInt(this.selectedRow.getAttribute('aria-rowindex'), 10) - 1], dropIndex, 'below');
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
this.reorderRows([this.selectedRow.rowIndex], dropIndex, 'below');
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Reorders the flat data array of the TreeGrid and updates the index of each record.
|
|
331
|
+
*
|
|
332
|
+
* @param {ITreeData[]} currentData - The array of tree data records to reorder.
|
|
333
|
+
* @returns {ITreeData[]} The updated array of tree data records with indices set.
|
|
334
|
+
*/
|
|
335
|
+
private orderToIndex(currentData: ITreeData[]): ITreeData[] {
|
|
336
|
+
for (let i: number = 0; i < currentData.length; i++) {
|
|
337
|
+
currentData[parseInt(i.toString(), 10)].index = i;
|
|
338
|
+
if (!isNullOrUndefined(currentData[parseInt(i.toString(), 10)].parentItem)) {
|
|
339
|
+
const updatedParent: ITreeData = getValue('uniqueIDCollection.' + currentData[parseInt(i.toString(), 10)].parentUniqueID, this.parent);
|
|
340
|
+
currentData[parseInt(i.toString(), 10)].parentItem.index = updatedParent.index;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return currentData;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Handles the addition of new rows to the TreeGrid.
|
|
348
|
+
*
|
|
349
|
+
* @param {Object} e - The event object containing information about the rows being added.
|
|
350
|
+
* @param {number} e.toIndex - The index at which the new rows should be added in the TreeGrid.
|
|
351
|
+
* @param {Object[]} e.records - An array of the records to be added to the TreeGrid.
|
|
352
|
+
*
|
|
353
|
+
* @returns {void} This function does not return any value.
|
|
354
|
+
*/
|
|
355
|
+
private rowsAdded(e: { toIndex: number, records: Object[] }): void {
|
|
356
|
+
let draggedRecord: ITreeData;
|
|
357
|
+
const dragRecords: ITreeData[] = e.records;
|
|
358
|
+
for (let i: number = e.records.length - 1; i > -1; i--) {
|
|
359
|
+
draggedRecord = dragRecords[parseInt(i.toString(), 10)];
|
|
360
|
+
if (draggedRecord.parentUniqueID) {
|
|
361
|
+
const record: ITreeData[] = dragRecords.filter((data: ITreeData) => {
|
|
362
|
+
return data.uniqueID === draggedRecord.parentUniqueID;
|
|
363
|
+
});
|
|
364
|
+
if (record.length) {
|
|
365
|
+
const index: number = record[0].childRecords.indexOf(draggedRecord);
|
|
366
|
+
const parentRecord: ITreeData = record[0];
|
|
367
|
+
if (index !== -1) {
|
|
368
|
+
if (isNullOrUndefined(this.parent.idMapping)) {
|
|
369
|
+
parentRecord.childRecords.splice(index, 1);
|
|
370
|
+
if (!parentRecord.childRecords.length) {
|
|
371
|
+
parentRecord.hasChildRecords = false;
|
|
372
|
+
parentRecord.hasFilteredChildRecords = false;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
this.isDraggedWithChild = true;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (isNullOrUndefined(this.parent.dataSource as ITreeData[]) || !(this.parent.dataSource as ITreeData[]).length) {
|
|
381
|
+
const tObj: TreeGrid = this.parent;
|
|
382
|
+
let draggedRecord: ITreeData;
|
|
383
|
+
const dragRecords: ITreeData[] = e.records;
|
|
384
|
+
const dragLength: number = e.records.length;
|
|
385
|
+
for (let i: number = dragLength - 1; i > -1; i--) {
|
|
386
|
+
draggedRecord = dragRecords[parseInt(i.toString(), 10)];
|
|
387
|
+
if (!i && draggedRecord.hasChildRecords) {
|
|
388
|
+
draggedRecord.taskData[this.parent.parentIdMapping] = null;
|
|
389
|
+
}
|
|
390
|
+
const recordIndex1: number = 0;
|
|
391
|
+
if (!isNullOrUndefined(tObj.parentIdMapping)) {
|
|
392
|
+
tObj.childMapping = null;
|
|
393
|
+
}
|
|
394
|
+
if (!isNullOrUndefined(draggedRecord.taskData) && !isNullOrUndefined(tObj.childMapping) &&
|
|
395
|
+
!Object.prototype.hasOwnProperty.call(draggedRecord.taskData, tObj.childMapping)) {
|
|
396
|
+
draggedRecord.taskData[tObj.childMapping] = [];
|
|
397
|
+
}
|
|
398
|
+
if (!isNullOrUndefined(draggedRecord[tObj.childMapping])) {
|
|
399
|
+
if (Object.prototype.hasOwnProperty.call(draggedRecord, tObj.childMapping) &&
|
|
400
|
+
((draggedRecord[tObj.childMapping]) as ITreeData[]).length && !this.isDraggedWithChild &&
|
|
401
|
+
!isNullOrUndefined(tObj.parentIdMapping)) {
|
|
402
|
+
const childData: ITreeData[] = (draggedRecord[tObj.childMapping]) as ITreeData[];
|
|
403
|
+
for (let j: number = 0; j < childData.length; j++) {
|
|
404
|
+
if (dragRecords.indexOf(childData[parseInt(j.toString(), 10)]) === -1) {
|
|
405
|
+
dragRecords.splice(j, 0, childData[parseInt(j.toString(), 10)]);
|
|
406
|
+
childData[parseInt(j.toString(), 10)].taskData = extend({}, childData[parseInt(j.toString(), 10)]);
|
|
407
|
+
i += 1;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (Object.prototype.hasOwnProperty.call(draggedRecord, tObj.parentIdMapping)
|
|
413
|
+
&& draggedRecord[tObj.parentIdMapping] !== null
|
|
414
|
+
&& !this.isDraggedWithChild) {
|
|
415
|
+
draggedRecord.taskData[tObj.parentIdMapping] = null;
|
|
416
|
+
delete draggedRecord.parentItem;
|
|
417
|
+
delete draggedRecord.parentUniqueID;
|
|
418
|
+
}
|
|
419
|
+
if (isNullOrUndefined(tObj.dataSource as ITreeData[])) {
|
|
420
|
+
tObj.dataSource = [];
|
|
421
|
+
}
|
|
422
|
+
(tObj.dataSource as ITreeData[]).splice(recordIndex1, 0, draggedRecord.taskData);
|
|
423
|
+
}
|
|
424
|
+
tObj.setProperties({ dataSource: tObj.dataSource }, false);
|
|
425
|
+
} else {
|
|
426
|
+
for (let i: number = 0; i < dragRecords.length; i++) {
|
|
427
|
+
setValue('uniqueIDCollection.' + dragRecords[parseInt(i.toString(), 10)].uniqueID, dragRecords[parseInt(i.toString(), 10)], this.parent);
|
|
428
|
+
}
|
|
429
|
+
const args: RowDropEventArgs = { data: e.records, dropIndex: e.toIndex };
|
|
430
|
+
if (this.parent.dataSource instanceof DataManager) {
|
|
431
|
+
this.treeGridData = this.parent.dataSource.dataSource.json;
|
|
432
|
+
this.treeData = this.parent.dataSource.dataSource.json;
|
|
433
|
+
} else {
|
|
434
|
+
this.treeGridData = this.parent.grid.dataSource as ITreeData[];
|
|
435
|
+
this.treeData = this.parent.dataSource as ITreeData[];
|
|
436
|
+
}
|
|
437
|
+
if (isNullOrUndefined(this.dropPosition)) {
|
|
438
|
+
this.dropPosition = 'bottomSegment';
|
|
439
|
+
args.dropIndex = this.parent.getCurrentViewRecords().length > 1 ? this.parent.getCurrentViewRecords().length - 1 :
|
|
440
|
+
args.dropIndex;
|
|
441
|
+
args.data = args.data.map((i: ITreeData) => {
|
|
442
|
+
if (i.hasChildRecords && isNullOrUndefined(i.parentItem)) {
|
|
443
|
+
i.level = 0;
|
|
444
|
+
return i;
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
delete i.parentItem;
|
|
448
|
+
delete i.parentUniqueID;
|
|
449
|
+
i.level = 0;
|
|
450
|
+
return i;
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
this.dropRows(args);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Handles the removal of specified rows from the TreeGrid.
|
|
460
|
+
*
|
|
461
|
+
* @param {Object} e - The event object containing information about the removed rows.
|
|
462
|
+
* @param {number[]} e.indexes - An array of indexes of the rows that were removed.
|
|
463
|
+
* @param {Object[]} e.records - An array of the records corresponding to the removed rows.
|
|
464
|
+
*
|
|
465
|
+
* @returns {void} This function does not return any value.
|
|
466
|
+
*/
|
|
467
|
+
private rowsRemoved(e: { indexes: number[], records: Object[] }): void {
|
|
468
|
+
for (let i: number = 0; i < e.records.length; i++) {
|
|
469
|
+
this.draggedRecord = e.records[parseInt(i.toString(), 10)];
|
|
470
|
+
if (this.draggedRecord.hasChildRecords || this.draggedRecord.parentItem &&
|
|
471
|
+
(this.parent.grid.dataSource as ITreeData[]).
|
|
472
|
+
indexOf(this.getChildrecordsByParentID(this.draggedRecord.parentUniqueID)[0]) !== -1 ||
|
|
473
|
+
this.draggedRecord.level === 0) {
|
|
474
|
+
this.deleteDragRow();
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Refreshes the data source of the TreeGrid.
|
|
481
|
+
*
|
|
482
|
+
* @returns {void} This function does not return any value.
|
|
483
|
+
*/
|
|
484
|
+
private refreshGridDataSource(): void {
|
|
485
|
+
const draggedRecord: ITreeData = this.draggedRecord;
|
|
486
|
+
const droppedRecord: ITreeData = this.droppedRecord;
|
|
487
|
+
const proxy: TreeGrid = this.parent;
|
|
488
|
+
let temporaryDataSource: Object; let indexOfDroppedRecord: number;
|
|
489
|
+
if (this.parent.dataSource instanceof DataManager && isOffline(this.parent)) {
|
|
490
|
+
temporaryDataSource = (<DataManager>proxy.dataSource).dataSource.json;
|
|
491
|
+
} else {
|
|
492
|
+
temporaryDataSource = proxy.dataSource;
|
|
493
|
+
}
|
|
494
|
+
if (temporaryDataSource && (!isNullOrUndefined(droppedRecord) && !droppedRecord.parentItem)
|
|
495
|
+
&& !isNullOrUndefined(droppedRecord.taskData)) {
|
|
496
|
+
const keys: string[] = Object.keys(temporaryDataSource);
|
|
497
|
+
for (let i: number = 0; i < keys.length; i++) {
|
|
498
|
+
if (temporaryDataSource[parseInt(i.toString(), 10)][this.parent.childMapping] ===
|
|
499
|
+
droppedRecord.taskData[this.parent.childMapping]) {
|
|
500
|
+
indexOfDroppedRecord = i;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
if (!this.parent.idMapping) {
|
|
504
|
+
const positionAdjustment: number = this.dropPosition === 'topSegment' ? 0 : 1;
|
|
505
|
+
if (this.dropPosition === 'topSegment' || this.dropPosition === 'bottomSegment') {
|
|
506
|
+
(temporaryDataSource as ITreeData[]).splice(indexOfDroppedRecord + positionAdjustment, 0, draggedRecord.taskData);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
} else if (!this.parent.parentIdMapping && (!isNullOrUndefined(droppedRecord) && droppedRecord.parentItem)) {
|
|
510
|
+
if (this.dropPosition === 'topSegment' || this.dropPosition === 'bottomSegment') {
|
|
511
|
+
const record: ITreeData = (this.getChildrecordsByParentID(droppedRecord.parentUniqueID) as ITreeData)[0];
|
|
512
|
+
const childRecords: ITreeData[] = record.childRecords;
|
|
513
|
+
for (let i: number = 0; i < childRecords.length; i++) {
|
|
514
|
+
droppedRecord.parentItem.taskData[this.parent.childMapping][parseInt(i.toString(), 10)]
|
|
515
|
+
= childRecords[parseInt(i.toString(), 10)].taskData;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (this.parent.parentIdMapping) {
|
|
521
|
+
if (draggedRecord.parentItem) {
|
|
522
|
+
if (this.dropPosition === 'topSegment' || this.dropPosition === 'bottomSegment') {
|
|
523
|
+
draggedRecord[this.parent.parentIdMapping] = droppedRecord[this.parent.parentIdMapping];
|
|
524
|
+
draggedRecord.taskData[this.parent.parentIdMapping] = droppedRecord[this.parent.parentIdMapping];
|
|
525
|
+
} else {
|
|
526
|
+
draggedRecord[this.parent.parentIdMapping] = droppedRecord[this.parent.idMapping];
|
|
527
|
+
draggedRecord.taskData[this.parent.parentIdMapping] = droppedRecord[this.parent.idMapping];
|
|
528
|
+
}
|
|
529
|
+
} else {
|
|
530
|
+
draggedRecord.taskData[this.parent.parentIdMapping] = null;
|
|
531
|
+
draggedRecord[this.parent.parentIdMapping] = null;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Removes the border from the first row of the TreeGrid.
|
|
538
|
+
*
|
|
539
|
+
* @param {HTMLTableRowElement} element - The table row element from which to remove the border.
|
|
540
|
+
* @returns {void} This function does not return any value.
|
|
541
|
+
*/
|
|
542
|
+
private removeFirstrowBorder(element: HTMLTableRowElement): void {
|
|
543
|
+
const canremove: boolean = this.dropPosition === 'bottomSegment';
|
|
544
|
+
if (this.parent.element.getElementsByClassName('e-firstrow-border').length > 0 && element &&
|
|
545
|
+
((element as HTMLTableRowElement).rowIndex !== 0 || canremove)) {
|
|
546
|
+
this.parent.element.getElementsByClassName('e-firstrow-border')[0].remove();
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Removes the border from the last row of the TreeGrid.
|
|
552
|
+
*
|
|
553
|
+
* @param {HTMLTableRowElement} element - The row element from which to remove the last row border.
|
|
554
|
+
* @returns {void}
|
|
555
|
+
*/
|
|
556
|
+
private removeLastrowBorder(element: HTMLTableRowElement): void {
|
|
557
|
+
if (!element) { return; }
|
|
558
|
+
const isEmptyRow: boolean = element.classList.contains('e-emptyrow') ||
|
|
559
|
+
element.classList.contains('e-columnheader') ||
|
|
560
|
+
element.classList.contains('e-detailrow');
|
|
561
|
+
if (isEmptyRow) { return; }
|
|
562
|
+
const lastRow: HTMLTableRowElement = this.parent.enableVirtualization ?
|
|
563
|
+
this.parent.getRows()[this.parent.getCurrentViewRecords().length - 1] as HTMLTableRowElement :
|
|
564
|
+
this.parent.getRowByIndex(this.parent.getCurrentViewRecords().length - 1) as HTMLTableRowElement;
|
|
565
|
+
const isNotLastRow: boolean = lastRow.getAttribute('data-uid') !== element.getAttribute('data-uid');
|
|
566
|
+
const canRemove: boolean = isNotLastRow || this.dropPosition === 'topSegment';
|
|
567
|
+
const lastRowBorderElement: HTMLElement = this.parent.element.getElementsByClassName('e-lastrow-border')[0] as HTMLElement;
|
|
568
|
+
if (lastRowBorderElement && canRemove) {
|
|
569
|
+
lastRowBorderElement.remove();
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Updates the icons associated with the specified rows in the TreeGrid.
|
|
575
|
+
*
|
|
576
|
+
* @param {Element[]} row - The array of row elements to update the icons for.
|
|
577
|
+
* @param {number} index - The index of the row being updated.
|
|
578
|
+
* @param {RowDragEventArgs} args - The event arguments associated with the row drag operation.
|
|
579
|
+
* @returns {string} The drop position ('topSegment', 'middleSegment', 'bottomSegment', or 'Invalid').
|
|
580
|
+
*/
|
|
581
|
+
private updateIcon(row: Element[], index: number, args: RowDragEventArgs): string {
|
|
582
|
+
const rowEle: Element = args.target ? closest(args.target, 'tr') : null;
|
|
583
|
+
this.dropPosition = undefined;
|
|
584
|
+
let rowPositionHeight: number = 0;
|
|
585
|
+
this.removeFirstrowBorder(rowEle as HTMLTableRowElement);
|
|
586
|
+
this.removeLastrowBorder(rowEle as HTMLTableRowElement);
|
|
587
|
+
for (let i: number = 0; i < args.rows.length; i++) {
|
|
588
|
+
if (!isNullOrUndefined(rowEle) && rowEle.getAttribute('data-uid') === args.rows[parseInt(i.toString(), 10)].getAttribute('data-uid')
|
|
589
|
+
|| !parentsUntil(args.target, 'e-gridcontent')) {
|
|
590
|
+
this.dropPosition = 'Invalid';
|
|
591
|
+
this.addErrorElem();
|
|
592
|
+
if (isNullOrUndefined(this.parent.rowDropSettings.targetID)) {
|
|
593
|
+
this.removetopOrBottomBorder();
|
|
594
|
+
this.removeChildBorder();
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
// To get the corresponding drop position related to mouse position
|
|
599
|
+
const tObj: TreeGrid = this.parent;
|
|
600
|
+
let rowTop: number = 0;
|
|
601
|
+
const roundOff: number = 0;
|
|
602
|
+
const toolHeight: number = tObj.toolbar && tObj.toolbar.length ?
|
|
603
|
+
document.getElementById(tObj.element.id + '_gridcontrol_toolbarItems').offsetHeight : 0;
|
|
604
|
+
// tObj.lastRow = tObj.getRowByIndex(tObj.getCurrentViewRecords().length - 1);
|
|
605
|
+
const positionOffSet: PositionOffSet = this.getOffset(tObj.element);
|
|
606
|
+
// let contentHeight1: number = (tObj.element.offsetHeight - (tObj.getContent() as HTMLElement).offsetHeight) + positionOffSet.top;
|
|
607
|
+
const contentHeight: number = (tObj.getHeaderContent() as HTMLElement).offsetHeight + positionOffSet.top + toolHeight;
|
|
608
|
+
const scrollTop: number = (tObj.getContent() as HTMLElement).firstElementChild.scrollTop;
|
|
609
|
+
if (!isNullOrUndefined(rowEle)) {
|
|
610
|
+
rowPositionHeight = (rowEle as HTMLElement).offsetTop - scrollTop;
|
|
611
|
+
}
|
|
612
|
+
// let scrollTop = (tObj.grid.scrollModule as any).content.scrollTop;
|
|
613
|
+
if (this.parent.enableVirtualization) {
|
|
614
|
+
rowTop = rowEle.getBoundingClientRect().top;
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
rowTop = rowPositionHeight + contentHeight + roundOff;
|
|
618
|
+
}
|
|
619
|
+
const rowBottom: number = (row[0] as HTMLElement).offsetHeight !== 0 && isNullOrUndefined(rowEle) ?
|
|
620
|
+
rowTop + (row[0] as HTMLElement).offsetHeight : rowTop + (rowEle as HTMLElement).offsetHeight;
|
|
621
|
+
const difference: number = rowBottom - rowTop;
|
|
622
|
+
const divide: number = difference / 3;
|
|
623
|
+
const topRowSegment: number = rowTop + divide;
|
|
624
|
+
const middleRowSegment: number = topRowSegment + divide;
|
|
625
|
+
const bottomRowSegment: number = middleRowSegment + divide;
|
|
626
|
+
const mouseEvent: MouseEvent = getObject('originalEvent.event', args);
|
|
627
|
+
const touchEvent: TouchEvent = getObject('originalEvent.event', args);
|
|
628
|
+
let posy: number = (mouseEvent.type === 'mousemove') ? mouseEvent.pageY : ((!isNullOrUndefined(touchEvent) &&
|
|
629
|
+
!isNullOrUndefined(touchEvent.changedTouches)) ? touchEvent.changedTouches[0].pageY : null);
|
|
630
|
+
if (this.parent.enableVirtualization) {
|
|
631
|
+
posy = (mouseEvent.type === 'mousemove') ? mouseEvent.clientY : ((!isNullOrUndefined(touchEvent) &&
|
|
632
|
+
!isNullOrUndefined(touchEvent.changedTouches)) ? touchEvent.changedTouches[0].clientY : null);
|
|
633
|
+
}
|
|
634
|
+
const isTopSegment: boolean = posy <= topRowSegment;
|
|
635
|
+
const isMiddleRowSegment: boolean = (posy > topRowSegment && posy <= middleRowSegment);
|
|
636
|
+
const isBottomRowSegment: boolean = (posy > middleRowSegment && posy <= bottomRowSegment);
|
|
637
|
+
let isBorderNeed: boolean = true;
|
|
638
|
+
if (isTopSegment || isMiddleRowSegment || isBottomRowSegment) {
|
|
639
|
+
if (isTopSegment && this.dropPosition !== 'Invalid') {
|
|
640
|
+
this.removeChildBorder();
|
|
641
|
+
this.dropPosition = 'topSegment';
|
|
642
|
+
this.removetopOrBottomBorder();
|
|
643
|
+
this.addFirstrowBorder(rowEle as HTMLTableRowElement);
|
|
644
|
+
this.removeErrorElem();
|
|
645
|
+
this.removeLastrowBorder(rowEle as HTMLTableRowElement);
|
|
646
|
+
}
|
|
647
|
+
if (isMiddleRowSegment && this.dropPosition !== 'Invalid') {
|
|
648
|
+
this.removetopOrBottomBorder();
|
|
649
|
+
this.dropPosition = 'middleSegment';
|
|
650
|
+
this.addLastRowborder(rowEle as HTMLTableRowElement);
|
|
651
|
+
this.addFirstrowBorder(rowEle as HTMLTableRowElement);
|
|
652
|
+
}
|
|
653
|
+
if (isBottomRowSegment && this.dropPosition !== 'Invalid') {
|
|
654
|
+
this.removeErrorElem();
|
|
655
|
+
this.removetopOrBottomBorder();
|
|
656
|
+
this.removeChildBorder();
|
|
657
|
+
this.dropPosition = 'bottomSegment';
|
|
658
|
+
this.addLastRowborder(rowEle as HTMLTableRowElement);
|
|
659
|
+
this.removeFirstrowBorder(rowEle as HTMLTableRowElement);
|
|
660
|
+
}
|
|
661
|
+
if ((isTopSegment || isBottomRowSegment) && this.dropPosition !== 'Invalid') {
|
|
662
|
+
isBorderNeed = this.updateBorderStatus(row, index);
|
|
663
|
+
this.topOrBottomBorder(args.target, isBorderNeed);
|
|
664
|
+
}
|
|
665
|
+
else if (isMiddleRowSegment && this.dropPosition !== 'Invalid') {
|
|
666
|
+
let rowElement: HTMLElement[] = [];
|
|
667
|
+
const element: Element = closest(args.target, 'tr');
|
|
668
|
+
rowElement = [].slice.call(element.querySelectorAll('.e-rowcell,.e-rowdragdrop,.e-detailrowcollapse'));
|
|
669
|
+
isBorderNeed = this.updateBorderStatus(row, index);
|
|
670
|
+
if (rowElement.length > 0 && isBorderNeed) {
|
|
671
|
+
this.addRemoveClasses(rowElement, true, 'e-childborder');
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return this.dropPosition;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Updates the border status for a specified row and index.
|
|
680
|
+
*
|
|
681
|
+
* @private
|
|
682
|
+
* @param {Element[]} row - The array of row elements to be updated.
|
|
683
|
+
* @param {number} index - The index of the row element for which the border status is to be updated.
|
|
684
|
+
* @returns {boolean} - Returns true if the border status was successfully updated, otherwise false.
|
|
685
|
+
*/
|
|
686
|
+
private updateBorderStatus(row: Element[], index: number): boolean {
|
|
687
|
+
let isBorderNeed: boolean = true;
|
|
688
|
+
let rows: any[] = this.parent.grid.getRows();
|
|
689
|
+
const childRows: any[] = [];
|
|
690
|
+
let hasDetailTemplate: boolean = false;
|
|
691
|
+
if (!isNullOrUndefined(this.parent.detailTemplate)) {
|
|
692
|
+
rows = this.parent.getDataRows();
|
|
693
|
+
hasDetailTemplate = true;
|
|
694
|
+
}
|
|
695
|
+
const treegridColumnIndex: number = this.parent.treeColumnIndex;
|
|
696
|
+
let treeColIndex: number = this.parent.allowRowDragAndDrop ?
|
|
697
|
+
(hasDetailTemplate ? treegridColumnIndex + 2 : treegridColumnIndex + 1) :
|
|
698
|
+
(hasDetailTemplate ? treegridColumnIndex + 1 : treegridColumnIndex);
|
|
699
|
+
if (!isNullOrUndefined(this.parent.rowDropSettings.targetID)) {
|
|
700
|
+
treeColIndex = treegridColumnIndex;
|
|
701
|
+
}
|
|
702
|
+
const dragRows: any[] = row;
|
|
703
|
+
const targetRow: any[] = [rows[`${index}`]];
|
|
704
|
+
if (this.dropPosition === 'topSegment') {
|
|
705
|
+
row.filter((e: any) => {
|
|
706
|
+
if (isNullOrUndefined(e) || isNullOrUndefined(e.cells) || isNullOrUndefined(targetRow[0]) ||
|
|
707
|
+
isNullOrUndefined(targetRow[0].cells)) {
|
|
708
|
+
return true;
|
|
709
|
+
}
|
|
710
|
+
const regex: RegExp = /index(\d+)|level(\d+)/g;
|
|
711
|
+
const parentIndexLevel: number = e === null || e === undefined ? undefined : e.cells[`${treeColIndex}`].className.match(regex);
|
|
712
|
+
const dropIndexLevel: number = targetRow[0].cells[`${treeColIndex}`].className.match(regex);
|
|
713
|
+
if (isNullOrUndefined(dropIndexLevel) || isNullOrUndefined(dropIndexLevel) || isNullOrUndefined(parentIndexLevel)) {
|
|
714
|
+
return true;
|
|
715
|
+
}
|
|
716
|
+
const parentLevel: number = +parentIndexLevel[1].match(/\d+/)[0];
|
|
717
|
+
const dropParentLevel: number = +dropIndexLevel[1].match(/\d+/)[0];
|
|
718
|
+
let InDraggedRowIndex: boolean = false;
|
|
719
|
+
if (parentLevel !== 0 && parentLevel !== dropParentLevel) {
|
|
720
|
+
return true;
|
|
721
|
+
}
|
|
722
|
+
for (let i: number = 0; i < rows.length; i++) {
|
|
723
|
+
if (rows[parseInt(i.toString(), 10)] === dragRows[0]) {
|
|
724
|
+
InDraggedRowIndex = true;
|
|
725
|
+
}
|
|
726
|
+
if (InDraggedRowIndex && rows[parseInt(i.toString(), 10)] !== dragRows[0]) {
|
|
727
|
+
const parentIndexLevelInRow: any = rows[parseInt(i.toString(), 10)].cells[`${treeColIndex}`].className.match(regex);
|
|
728
|
+
const parentLevelInRow: number = +parentIndexLevelInRow[1].match(/\d+/)[0];
|
|
729
|
+
if (parentLevelInRow !== parentLevel && parentLevelInRow > parentLevel) {
|
|
730
|
+
childRows.push(rows[parseInt(i.toString(), 10)]);
|
|
731
|
+
} else {
|
|
732
|
+
break;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
if (parentLevel === dropParentLevel && ((childRows.length > 0 && parseInt(row[0].getAttribute('aria-rowindex')!, 10) - 1 === index - (childRows.length + 1)) || (childRows.length === 0 && parseInt(row[0].getAttribute('aria-rowindex')!, 10) - 1 === index - 1))) {
|
|
737
|
+
isBorderNeed = false;
|
|
738
|
+
}
|
|
739
|
+
return true;
|
|
740
|
+
});
|
|
741
|
+
isBorderNeed = (!isNullOrUndefined(row) && childRows.length === 0 && !isNullOrUndefined(row[0].getAttribute('aria-rowindex')) && parseInt(row[0].getAttribute('aria-rowindex'), 10) - 1 === index - 1) && isNullOrUndefined(row[0]) ? false : isBorderNeed;
|
|
742
|
+
}
|
|
743
|
+
if (this.dropPosition === 'bottomSegment') {
|
|
744
|
+
targetRow.filter((e: any) => {
|
|
745
|
+
if (isNullOrUndefined(e) || isNullOrUndefined(e.cells) || isNullOrUndefined(dragRows[0]) ||
|
|
746
|
+
isNullOrUndefined(dragRows[0].cells)) {
|
|
747
|
+
return true;
|
|
748
|
+
}
|
|
749
|
+
const regex: RegExp = /index(\d+)|level(\d+)/g;
|
|
750
|
+
const parentIndexLevel: number = e === null || e === undefined ? undefined : e.cells[`${treeColIndex}`].className.match(regex);
|
|
751
|
+
const dragIndexLevel: number = dragRows[0].cells[`${treeColIndex}`].className.match(regex);
|
|
752
|
+
if (isNullOrUndefined(dragIndexLevel) || isNullOrUndefined(parentIndexLevel)) {
|
|
753
|
+
return true;
|
|
754
|
+
}
|
|
755
|
+
const parentLevel: number = +parentIndexLevel[1].match(/\d+/)[0];
|
|
756
|
+
const dragParentLevel: number = +dragIndexLevel[1].match(/\d+/)[0];
|
|
757
|
+
let InDraggedRowIndex: boolean = false;
|
|
758
|
+
if (parentLevel !== 0 && parentLevel !== dragParentLevel) {
|
|
759
|
+
return true;
|
|
760
|
+
}
|
|
761
|
+
for (let i: number = 0; i < rows.length; i++) {
|
|
762
|
+
if (rows[parseInt(i.toString(), 10)] === targetRow[0]) {
|
|
763
|
+
InDraggedRowIndex = true;
|
|
764
|
+
}
|
|
765
|
+
if (InDraggedRowIndex && rows[parseInt(i.toString(), 10)] !== targetRow[0]) {
|
|
766
|
+
const parentIndexLevelInRow: any = rows[parseInt(i.toString(), 10)].cells[`${treeColIndex}`].className.match(regex);
|
|
767
|
+
const parentLevelInRow: number = +parentIndexLevelInRow[1].match(/\d+/)[0];
|
|
768
|
+
if (parentLevelInRow !== parentLevel && parentLevelInRow > parentLevel) {
|
|
769
|
+
childRows.push(rows[parseInt(i.toString(), 10)]);
|
|
770
|
+
} else {
|
|
771
|
+
break;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
if (!isNullOrUndefined(row) && parentLevel === dragParentLevel && ((childRows.length > 0 && !isNullOrUndefined(row[0].getAttribute('aria-rowindex')) && parseInt(row[0].getAttribute('aria-rowindex'), 10) - 1 === index + (childRows.length + 1)) || (childRows.length === 0 && !isNullOrUndefined(row[0].getAttribute('aria-rowindex')) && parseInt(row[0].getAttribute('aria-rowindex'), 10) - 1 === index + 1))) {
|
|
776
|
+
isBorderNeed = false;
|
|
777
|
+
}
|
|
778
|
+
return true;
|
|
779
|
+
});
|
|
780
|
+
isBorderNeed = (!isNullOrUndefined(row) && childRows.length === 0 && !isNullOrUndefined(row[0].getAttribute('aria-rowindex')) && parseInt(row[0].getAttribute('aria-rowindex'), 10) - 1 === index + 1) && isNullOrUndefined(row[0]) ? false : isBorderNeed;
|
|
781
|
+
}
|
|
782
|
+
if (this.dropPosition === 'middleSegment') {
|
|
783
|
+
targetRow.filter((e: any) => {
|
|
784
|
+
if (isNullOrUndefined(e) || isNullOrUndefined(e.cells) || isNullOrUndefined(dragRows[0]) ||
|
|
785
|
+
isNullOrUndefined(dragRows[0].cells)) {
|
|
786
|
+
return true;
|
|
787
|
+
}
|
|
788
|
+
for (let i: number = 0; i < dragRows.length; i++) {
|
|
789
|
+
const regex: RegExp = /index(\d+)|level(\d+)/g;
|
|
790
|
+
let dropActualIndex: number = targetRow[0].rowIndex;
|
|
791
|
+
const dragIndexLevel: RegExpMatchArray | null = dragRows[parseInt(i.toString(), 10)].cells[`${treeColIndex}`].className.match(regex);
|
|
792
|
+
if (!dragIndexLevel) { return true; }
|
|
793
|
+
const dragIndex: number = parseInt(dragIndexLevel.find((item: string) => item.includes('index')).match(/\d+/)[0] || '0', 10);
|
|
794
|
+
if (hasDetailTemplate) {
|
|
795
|
+
dropActualIndex = dropActualIndex / 2;
|
|
796
|
+
}
|
|
797
|
+
if (dragIndex === dropActualIndex && !this.parent.rowDropSettings.targetID) {
|
|
798
|
+
isBorderNeed = false;
|
|
799
|
+
}
|
|
800
|
+
else {
|
|
801
|
+
isBorderNeed = true;
|
|
802
|
+
break;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
if (!isBorderNeed) {
|
|
806
|
+
this.dropPosition = 'Invalid';
|
|
807
|
+
this.addErrorElem();
|
|
808
|
+
}
|
|
809
|
+
return isBorderNeed;
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
this.canDrop = isBorderNeed;
|
|
813
|
+
return isBorderNeed;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* Removes the visual border from all child rows within the TreeGrid.
|
|
818
|
+
*
|
|
819
|
+
* @returns {void} No return value.
|
|
820
|
+
*/
|
|
821
|
+
private removeChildBorder(): void {
|
|
822
|
+
let borderElem: HTMLElement[] = [];
|
|
823
|
+
borderElem = [].slice.call(this.parent.element.querySelectorAll('.e-childborder'));
|
|
824
|
+
if (borderElem.length > 0) {
|
|
825
|
+
this.addRemoveClasses(borderElem, false, 'e-childborder');
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* Adds a visual border to the first row of the TreeGrid.
|
|
831
|
+
*
|
|
832
|
+
* @param {HTMLTableRowElement} targetRow - The target row element to which the border will be added, if it is the first row.
|
|
833
|
+
* @returns {void} No return value.
|
|
834
|
+
*/
|
|
835
|
+
private addFirstrowBorder(targetRow: HTMLTableRowElement): void {
|
|
836
|
+
const node: Element = this.parent.element;
|
|
837
|
+
const tObj: TreeGrid = this.parent;
|
|
838
|
+
if (targetRow && targetRow.rowIndex === 0 && !targetRow.classList.contains('e-emptyrow')) {
|
|
839
|
+
const div: HTMLElement = this.parent.createElement('div', { className: 'e-firstrow-border' });
|
|
840
|
+
const gridheaderEle: Element = this.parent.getHeaderContent();
|
|
841
|
+
let toolbarHeight: number = 0;
|
|
842
|
+
if (tObj.toolbar) {
|
|
843
|
+
toolbarHeight = (tObj.toolbarModule.getToolbar() as HTMLElement).offsetHeight;
|
|
844
|
+
}
|
|
845
|
+
const multiplegrid: boolean = !isNullOrUndefined(this.parent.rowDropSettings.targetID);
|
|
846
|
+
if (multiplegrid) {
|
|
847
|
+
div.style.top = (this.parent.grid.element.getElementsByClassName('e-gridheader')[0] as HTMLElement).offsetHeight
|
|
848
|
+
+ toolbarHeight + 'px';
|
|
849
|
+
}
|
|
850
|
+
div.style.width = multiplegrid ? (node as HTMLElement).offsetWidth + 'px' :
|
|
851
|
+
(node as HTMLElement).offsetWidth - this.getScrollWidth() + 'px';
|
|
852
|
+
if (!gridheaderEle.querySelectorAll('.e-firstrow-border').length) {
|
|
853
|
+
gridheaderEle.appendChild(div);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Adds a visual border to the last row of the TreeGrid.
|
|
860
|
+
*
|
|
861
|
+
* @param {HTMLTableRowElement} trElement - The table row element to which the border will be added, if it is the last row.
|
|
862
|
+
* @returns {void} No return value.
|
|
863
|
+
*/
|
|
864
|
+
private addLastRowborder(trElement: HTMLTableRowElement): void {
|
|
865
|
+
if (!trElement) { return; }
|
|
866
|
+
const isEmptyRow: boolean = trElement && (trElement.classList.contains('e-emptyrow') ||
|
|
867
|
+
trElement.classList.contains('e-columnheader') || trElement.classList.contains('e-detailrow'));
|
|
868
|
+
if (isEmptyRow) { return; }
|
|
869
|
+
if (trElement && !isEmptyRow && this.parent.getRows()[this.parent.getCurrentViewRecords().length - 1].getAttribute('data-uid') ===
|
|
870
|
+
trElement.getAttribute('data-uid')) {
|
|
871
|
+
const bottomborder: HTMLElement = this.parent.createElement('div', { className: 'e-lastrow-border' });
|
|
872
|
+
const gridcontentEle: Element = this.parent.getContent();
|
|
873
|
+
bottomborder.style.width = (this.parent.element as HTMLElement).offsetWidth - this.getScrollWidth() + 'px';
|
|
874
|
+
if (!gridcontentEle.querySelectorAll('.e-lastrow-border').length) {
|
|
875
|
+
gridcontentEle.classList.add('e-treegrid-relative');
|
|
876
|
+
gridcontentEle.appendChild(bottomborder);
|
|
877
|
+
bottomborder.style.bottom = this.getScrollWidth() + 'px';
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/**
|
|
883
|
+
* Retrieves the total scroll width of the TreeGrid content area.
|
|
884
|
+
*
|
|
885
|
+
* @returns {number} The width of the scrollbar if content overflows, otherwise 0.
|
|
886
|
+
*/
|
|
887
|
+
private getScrollWidth(): number {
|
|
888
|
+
const scrollElem: HTMLElement = this.parent.getContent().firstElementChild as HTMLElement;
|
|
889
|
+
return scrollElem.scrollWidth > scrollElem.offsetWidth ? Scroll.getScrollBarWidth() : 0;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* Adds an error element to the dragged row element during a row drag-and-drop operation.
|
|
894
|
+
*
|
|
895
|
+
* @returns {void} No return value.
|
|
896
|
+
*/
|
|
897
|
+
private addErrorElem(): void {
|
|
898
|
+
const dragelem: Element = document.getElementsByClassName('e-cloneproperties')[0];
|
|
899
|
+
const errorelemCount: number = dragelem.querySelectorAll('.e-errorelem').length;
|
|
900
|
+
const sanitize: string = 'sanitize';
|
|
901
|
+
if (!errorelemCount && !this.parent.rowDropSettings.targetID) {
|
|
902
|
+
const errorContainer: HTMLElement = document.createElement('div');
|
|
903
|
+
errorContainer.classList.add('e-errorcontainer', 'e-icons', 'e-errorelem');
|
|
904
|
+
const rowCell: HTMLElement = dragelem.querySelector('.e-rowcell') as HTMLElement;
|
|
905
|
+
const errorVal: Element = dragelem.querySelector('.errorValue');
|
|
906
|
+
let content: string = rowCell.innerHTML;
|
|
907
|
+
if (errorVal) {
|
|
908
|
+
content = this.parent[`${sanitize}`](errorVal.innerHTML);
|
|
909
|
+
errorVal.parentNode.removeChild(errorVal);
|
|
910
|
+
}
|
|
911
|
+
rowCell.innerHTML = '';
|
|
912
|
+
const spanContent: HTMLElement = document.createElement('span');
|
|
913
|
+
spanContent.className = 'errorValue';
|
|
914
|
+
spanContent.style.paddingLeft = '16px';
|
|
915
|
+
spanContent.innerHTML = this.parent[`${sanitize}`](content);
|
|
916
|
+
rowCell.appendChild(errorContainer);
|
|
917
|
+
rowCell.appendChild(spanContent);
|
|
918
|
+
const dropItemSpan: HTMLElement = document.querySelector('.e-dropitemscount');
|
|
919
|
+
if (this.hasDropItem && dropItemSpan) {
|
|
920
|
+
const dropItemLeft: number = parseInt(dropItemSpan.style.left, 10) + errorContainer.offsetWidth + 16;
|
|
921
|
+
const spanLeft: number = !this.parent.enableRtl ? dropItemLeft : 0;
|
|
922
|
+
dropItemSpan.style.left = `${spanLeft}px`;
|
|
923
|
+
this.hasDropItem = false;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* Removes the error element from the DOM and adjusts the position of the drop item count if necessary.
|
|
930
|
+
*
|
|
931
|
+
* @returns {void} No return value.
|
|
932
|
+
*/
|
|
933
|
+
private removeErrorElem(): void {
|
|
934
|
+
const errorelem: HTMLElement = document.querySelector('.e-errorelem');
|
|
935
|
+
const errorValue: HTMLElement = document.querySelector('.errorValue');
|
|
936
|
+
const dropItemSpan: HTMLElement = document.querySelector('.e-dropitemscount');
|
|
937
|
+
if (errorelem) {
|
|
938
|
+
if (dropItemSpan) {
|
|
939
|
+
const dropItemLeft: number = parseInt(dropItemSpan.style.left, 10) - errorelem.offsetWidth - 16;
|
|
940
|
+
setStyleAttribute(errorValue, {
|
|
941
|
+
paddingLeft: '0px'
|
|
942
|
+
});
|
|
943
|
+
if (!this.parent.enableRtl) {
|
|
944
|
+
setStyleAttribute(dropItemSpan, {
|
|
945
|
+
left: `${dropItemLeft}px`
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
errorelem.remove();
|
|
950
|
+
}
|
|
951
|
+
this.hasDropItem = true;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* Applies drop border styles to row elements based on the current drop position ('topSegment' or 'bottomSegment').
|
|
956
|
+
*
|
|
957
|
+
* @param {Element} target - The target element where the drop action is taking place.
|
|
958
|
+
* @param {boolean} [isBorderNeed=true] - Indicates whether a border is needed during the drop action. Defaults to `true`.
|
|
959
|
+
* @returns {void} No return value.
|
|
960
|
+
*/
|
|
961
|
+
private topOrBottomBorder(target: Element, isBorderNeed: boolean = true): void {
|
|
962
|
+
const element: Element = closest(target, 'tr');
|
|
963
|
+
const rowElements: HTMLElement[] = element ?
|
|
964
|
+
Array.from(element.querySelectorAll('.e-rowcell, .e-rowdragdrop, .e-detailrowcollapse')) : [];
|
|
965
|
+
if (!rowElements.length) { return; }
|
|
966
|
+
const classAction: any = isBorderNeed ? this.addRemoveClasses.bind(this, rowElements, true) : this.addRemoveClasses.bind(this, rowElements, false, 'e-dragborder');
|
|
967
|
+
if (this.dropPosition === 'topSegment') {
|
|
968
|
+
classAction('e-droptop');
|
|
969
|
+
const lastRowDragBorder: Element = this.parent.element.querySelector('.e-lastrow-dragborder');
|
|
970
|
+
if (lastRowDragBorder) {
|
|
971
|
+
lastRowDragBorder.remove();
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
if (this.dropPosition === 'bottomSegment') {
|
|
975
|
+
classAction('e-dropbottom');
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
/**
|
|
980
|
+
* Removes the drop border classes ('e-dropbottom' and 'e-droptop') from the parent element if present.
|
|
981
|
+
*
|
|
982
|
+
* @returns {void} No return value.
|
|
983
|
+
*/
|
|
984
|
+
private removetopOrBottomBorder(): void {
|
|
985
|
+
let border: HTMLElement[] = [];
|
|
986
|
+
border = [].slice.call(this.parent.element.querySelectorAll('.e-dropbottom, .e-droptop'));
|
|
987
|
+
if (this.parent.rowDropSettings.targetID) {
|
|
988
|
+
border = [].slice.call(document.querySelectorAll('.e-dropbottom, .e-droptop'));
|
|
989
|
+
}
|
|
990
|
+
if (border.length) {
|
|
991
|
+
this.addRemoveClasses(border, false, 'e-dropbottom');
|
|
992
|
+
this.addRemoveClasses(border, false, 'e-droptop');
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
/**
|
|
997
|
+
* Adds or removes a specified class from a list of HTML elements.
|
|
998
|
+
*
|
|
999
|
+
* @param {Element[]} cells - The list of HTML elements to which the class will be added or removed.
|
|
1000
|
+
* @param {boolean} add - A flag indicating whether to add (`true`) or remove (`false`) the class.
|
|
1001
|
+
* @param {string} className - The class name to be added or removed from each element in `cells`.
|
|
1002
|
+
* @returns {void} No return value.
|
|
1003
|
+
*/
|
|
1004
|
+
private addRemoveClasses(cells: Element[], add: boolean, className: string): void {
|
|
1005
|
+
for (let i: number = 0, len: number = cells.length; i < len; i++) {
|
|
1006
|
+
if (add) {
|
|
1007
|
+
cells[parseInt(i.toString(), 10)].classList.add(className);
|
|
1008
|
+
} else {
|
|
1009
|
+
cells[parseInt(i.toString(), 10)].classList.remove(className);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
/**
|
|
1015
|
+
* Calculates the offset position of the specified HTML element relative to the document.
|
|
1016
|
+
*
|
|
1017
|
+
* @param {Element} element - The HTML element for which the offset position is calculated.
|
|
1018
|
+
* @returns {PositionOffSet} The offset position containing `top` and `left` values.
|
|
1019
|
+
*/
|
|
1020
|
+
private getOffset(element: Element): PositionOffSet {
|
|
1021
|
+
const box: DOMRect | ClientRect = element.getBoundingClientRect();
|
|
1022
|
+
const body: HTMLElement = document.body;
|
|
1023
|
+
const docElem: HTMLElement = document.documentElement;
|
|
1024
|
+
const scrollTop: number = window.pageYOffset || docElem.scrollTop || body.scrollTop;
|
|
1025
|
+
const scrollLeft: number = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;
|
|
1026
|
+
const clientTop: number = docElem.clientTop || body.clientTop || 0;
|
|
1027
|
+
const clientLeft: number = docElem.clientLeft || body.clientLeft || 0;
|
|
1028
|
+
const top: number = box.top + scrollTop - clientTop;
|
|
1029
|
+
const left: number = box.left + scrollLeft - clientLeft;
|
|
1030
|
+
return { top: Math.round(top), left: Math.round(left) };
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
/**
|
|
1034
|
+
* Handles the dragging of rows in the TreeGrid.
|
|
1035
|
+
*
|
|
1036
|
+
* @param {RowDragEventArgs} args - The event arguments for the row drag action.
|
|
1037
|
+
* @returns {void} This function does not return a value.
|
|
1038
|
+
*/
|
|
1039
|
+
private Rowdraging(args: RowDragEventArgs): void {
|
|
1040
|
+
const tObj: TreeGrid = this.parent;
|
|
1041
|
+
const cloneElement: HTMLElement = this.parent.element.querySelector('.e-cloneproperties') as HTMLElement;
|
|
1042
|
+
if (!cloneElement) { return; }
|
|
1043
|
+
cloneElement.style.cursor = '';
|
|
1044
|
+
const rowEle: Element = args.target ? closest(args.target, 'tr') : null;
|
|
1045
|
+
let rowIdx: number = -1;
|
|
1046
|
+
if (!isNullOrUndefined(this.parent.detailTemplate)) {
|
|
1047
|
+
rowIdx = rowEle ? this.parent.getDataRows().indexOf(rowEle as HTMLTableRowElement) : -1;
|
|
1048
|
+
}
|
|
1049
|
+
else {
|
|
1050
|
+
rowIdx = rowEle ? (rowEle as HTMLTableRowElement).rowIndex : -1;
|
|
1051
|
+
}
|
|
1052
|
+
if (rowIdx === -1) {
|
|
1053
|
+
this.canDrop = false;
|
|
1054
|
+
this.addErrorElem();
|
|
1055
|
+
this.removetopOrBottomBorder();
|
|
1056
|
+
this.removeChildBorder();
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
const dragRecords: ITreeData[] = Array.isArray(args.data) ? args.data : [args.data as ITreeData];
|
|
1060
|
+
let droppedRecord: ITreeData = tObj.getCurrentViewRecords()[parseInt(rowIdx.toString(), 10)];
|
|
1061
|
+
if (tObj.rowDropSettings.targetID) {
|
|
1062
|
+
const dropElement: Element = parentsUntil(args.target, 'e-treegrid');
|
|
1063
|
+
if (dropElement && dropElement.id === this.parent.rowDropSettings.targetID) {
|
|
1064
|
+
const srcControl: TreeGrid = (<EJ2Intance>dropElement).ej2_instances[0];
|
|
1065
|
+
droppedRecord = srcControl.getCurrentViewRecords()[parseInt(rowIdx.toString(), 10)];
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
this.removeErrorElem();
|
|
1069
|
+
this.canDrop = true;
|
|
1070
|
+
this.ensuredropPosition(dragRecords, droppedRecord);
|
|
1071
|
+
if (!tObj.rowDropSettings.targetID && this.canDrop && !isNullOrUndefined(args.rows[0])) {
|
|
1072
|
+
tObj.rowDragAndDropModule.updateIcon(args.rows, rowIdx, args);
|
|
1073
|
+
}
|
|
1074
|
+
if (tObj.rowDropSettings.targetID) {
|
|
1075
|
+
const dropElement: Element = parentsUntil(args.target, 'e-treegrid');
|
|
1076
|
+
if (dropElement && dropElement.id === this.parent.rowDropSettings.targetID) {
|
|
1077
|
+
const srcControl: TreeGrid = (<EJ2Intance>dropElement).ej2_instances[0];
|
|
1078
|
+
srcControl.rowDragAndDropModule.updateIcon(args.rows, rowIdx, args);
|
|
1079
|
+
this.dropPosition = srcControl.rowDragAndDropModule.dropPosition;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
if (args.target && closest(args.target, '#' + tObj.rowDropSettings.targetID)) {
|
|
1083
|
+
const dropElement: Element = parentsUntil(args.target, 'e-treegrid');
|
|
1084
|
+
if (!dropElement) {
|
|
1085
|
+
cloneElement.style.cursor = 'default';
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
/**
|
|
1091
|
+
* Handles the row drop event for the TreeGrid.
|
|
1092
|
+
*
|
|
1093
|
+
* @param {RowDropEventArgs} args - The event arguments for the row drop action.
|
|
1094
|
+
* @returns {void} This function does not return a value.
|
|
1095
|
+
*/
|
|
1096
|
+
private rowDropped(args: RowDropEventArgs): void {
|
|
1097
|
+
const tObj: TreeGrid = this.parent;
|
|
1098
|
+
const parentItem: string = 'parentItem';
|
|
1099
|
+
if (!tObj.rowDropSettings.targetID) {
|
|
1100
|
+
if (parentsUntil(args.target, 'e-content') || (this.dropPosition === 'Invalid' || !this.canDrop)) {
|
|
1101
|
+
if (this.parent.element.querySelector('.e-errorelem') || !this.canDrop) {
|
|
1102
|
+
this.dropPosition = 'Invalid';
|
|
1103
|
+
}
|
|
1104
|
+
setValue('dropPosition', this.dropPosition, args);
|
|
1105
|
+
tObj.trigger(events.rowDrop, args);
|
|
1106
|
+
if (!args.cancel) {
|
|
1107
|
+
if (!isCountRequired(this.parent) && (this.dropPosition === 'Invalid' && !this.canDrop)) {
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
if (!isCountRequired(this.parent)) {
|
|
1111
|
+
this.dropRows(args);
|
|
1112
|
+
}
|
|
1113
|
+
if (tObj.isLocalData) {
|
|
1114
|
+
tObj.flatData = this.orderToIndex(tObj.flatData);
|
|
1115
|
+
}
|
|
1116
|
+
tObj.grid.refresh();
|
|
1117
|
+
this.removeRowBorders();
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
} else {
|
|
1121
|
+
if (args.target && closest(args.target, '#' + tObj.rowDropSettings.targetID) || parentsUntil(args.target, 'e-treegrid') &&
|
|
1122
|
+
parentsUntil(args.target, 'e-treegrid').id === tObj.rowDropSettings.targetID || args.target && document.getElementById(tObj.rowDropSettings.targetID)) {
|
|
1123
|
+
if (this.parent.element.querySelector('.e-errorelem') || !this.canDrop) {
|
|
1124
|
+
this.dropPosition = 'Invalid';
|
|
1125
|
+
}
|
|
1126
|
+
setValue('dropPosition', this.dropPosition, args);
|
|
1127
|
+
tObj.trigger(events.rowDrop, args);
|
|
1128
|
+
if (!args.cancel && tObj.rowDropSettings.targetID) {
|
|
1129
|
+
if (this.dropPosition === 'Invalid' && !this.canDrop) {
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
this.dragDropGrid(args);
|
|
1133
|
+
if (tObj.isLocalData) {
|
|
1134
|
+
tObj.flatData = this.orderToIndex(tObj.flatData);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
this.removetopOrBottomBorder();
|
|
1140
|
+
this.removeChildBorder();
|
|
1141
|
+
this.removeRowBorders();
|
|
1142
|
+
if (this.parent.enableImmutableMode && !this.parent.allowPaging && !isNullOrUndefined(args.data[0][`${parentItem}`])) {
|
|
1143
|
+
let index: number = this.parent.treeColumnIndex;
|
|
1144
|
+
index = index + 1;
|
|
1145
|
+
const primaryKeyField: string = this.parent.getPrimaryKeyFieldNames()[0];
|
|
1146
|
+
let rowIndex: number = this.parent.grid.getRowIndexByPrimaryKey(args.data[0][`${primaryKeyField}`]);
|
|
1147
|
+
const row: HTMLTableRowElement = this.parent.getRows()[parseInt(rowIndex.toString(), 10)];
|
|
1148
|
+
let data: Object = args.data[0];
|
|
1149
|
+
if (this.dropPosition === 'middleSegment') {
|
|
1150
|
+
const record: Object[] = []; const rows: HTMLTableRowElement[] = [];
|
|
1151
|
+
record.push(data); rows.push(row);
|
|
1152
|
+
const parentUniqueID: string = 'parentUniqueID';
|
|
1153
|
+
data = getParentData(this.parent, args.data[0][`${parentUniqueID}`]);
|
|
1154
|
+
rowIndex = this.parent.grid.getRowIndexByPrimaryKey(data[`${primaryKeyField}`]);
|
|
1155
|
+
const parentrow: HTMLTableRowElement = this.parent.getRows()[parseInt(rowIndex.toString(), 10)];
|
|
1156
|
+
record.push(data); rows.push(parentrow);
|
|
1157
|
+
for (let i: number = 0; i < record.length; i++) {
|
|
1158
|
+
this.parent.renderModule.cellRender({
|
|
1159
|
+
data: record[parseInt(i.toString(), 10)],
|
|
1160
|
+
cell: rows[parseInt(i.toString(), 10)].cells[parseInt(index.toString(), 10)],
|
|
1161
|
+
column: this.parent.grid.getColumns()[this.parent.treeColumnIndex],
|
|
1162
|
+
requestType: 'rowDragAndDrop'
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
const targetEle: Element = parentrow.getElementsByClassName('e-treegridcollapse')[0];
|
|
1166
|
+
if (!isNullOrUndefined(targetEle)) {
|
|
1167
|
+
removeClass([targetEle], 'e-treegridcollapse');
|
|
1168
|
+
addClass([targetEle], 'e-treegridexpand');
|
|
1169
|
+
}
|
|
1170
|
+
} else {
|
|
1171
|
+
this.parent.renderModule.cellRender({
|
|
1172
|
+
data: data, cell: row.cells[parseInt(index.toString(), 10)],
|
|
1173
|
+
column: this.parent.grid.getColumns()[this.parent.treeColumnIndex],
|
|
1174
|
+
requestType: 'rowDragAndDrop'
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
/**
|
|
1181
|
+
* Removes the border elements for the first and last rows of the TreeGrid.
|
|
1182
|
+
*
|
|
1183
|
+
* @returns {void} This function does not return a value.
|
|
1184
|
+
*/
|
|
1185
|
+
private removeRowBorders(): void {
|
|
1186
|
+
['e-firstrow-border', 'e-lastrow-border'].forEach((className: string): void => {
|
|
1187
|
+
const element: HTMLElement = this.parent.element.getElementsByClassName(className)[0] as HTMLElement;
|
|
1188
|
+
if (element) {
|
|
1189
|
+
element.remove();
|
|
1190
|
+
}
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
/**
|
|
1195
|
+
* Handles the drag-and-drop operation between TreeGrids, updating the source and target grids.
|
|
1196
|
+
*
|
|
1197
|
+
* @param {RowDropEventArgs} args - The arguments related to the row drop event, including target information and data being dropped.
|
|
1198
|
+
* @returns {void} - This function does not return any value.
|
|
1199
|
+
*/
|
|
1200
|
+
private dragDropGrid(args: RowDropEventArgs): void {
|
|
1201
|
+
const tObj: TreeGrid = this.parent;
|
|
1202
|
+
const targetRow: HTMLTableRowElement = closest(args.target, 'tr') as HTMLTableRowElement;
|
|
1203
|
+
const targetIndex: number = isNaN(this.getTargetIdx(targetRow)) ? 0 : this.getTargetIdx(targetRow);
|
|
1204
|
+
const dropElement: Element = parentsUntil(args.target, 'e-treegrid');
|
|
1205
|
+
let srcControl: TreeGrid;
|
|
1206
|
+
if (dropElement && dropElement.id === this.parent.rowDropSettings.targetID && !isRemoteData(this.parent)
|
|
1207
|
+
&& !isCountRequired(this.parent)) {
|
|
1208
|
+
srcControl = (<EJ2Intance>dropElement).ej2_instances[0];
|
|
1209
|
+
let records: ITreeData[] = tObj.getSelectedRecords();
|
|
1210
|
+
const indexes: number[] = [];
|
|
1211
|
+
for (let i: number = 0; i < records.length; i++) {
|
|
1212
|
+
indexes[parseInt(i.toString(), 10)] = records[parseInt(i.toString(), 10)].index;
|
|
1213
|
+
}
|
|
1214
|
+
const data: ITreeData[] = srcControl.dataSource as ITreeData[];
|
|
1215
|
+
if (this.parent.idMapping !== null && (isNullOrUndefined(this.dropPosition) || this.dropPosition === 'bottomSegment' || this.dropPosition === 'Invalid') && !(data.length)) {
|
|
1216
|
+
const actualData: ITreeData[] = [];
|
|
1217
|
+
for (let i: number = 0; i < records.length; i++) {
|
|
1218
|
+
if (records[parseInt(i.toString(), 10)].hasChildRecords) {
|
|
1219
|
+
actualData.push(records[parseInt(i.toString(), 10)]);
|
|
1220
|
+
const child: ITreeData[] = findChildrenRecords(records[parseInt(i.toString(), 10)]);
|
|
1221
|
+
for (let i: number = 0; i < child.length; i++) {
|
|
1222
|
+
actualData.push(child[parseInt(i.toString(), 10)]); // push child records to drop the parent record along with its child records
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
if (actualData.length) {
|
|
1227
|
+
records = actualData;
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
tObj.notify(events.rowsRemove, { indexes: indexes, records: records });
|
|
1231
|
+
srcControl.notify(events.rowsAdd, { toIndex: targetIndex, records: records });
|
|
1232
|
+
const srcControlFlatData: ITreeData[] = srcControl.rowDragAndDropModule.treeGridData;
|
|
1233
|
+
if (!isNullOrUndefined(srcControlFlatData)) {
|
|
1234
|
+
for (let i: number = 0; i < srcControlFlatData.length; i++) {
|
|
1235
|
+
srcControlFlatData[parseInt(i.toString(), 10)].index = i;
|
|
1236
|
+
if (!isNullOrUndefined(srcControlFlatData[parseInt(i.toString(), 10)].parentItem)) {
|
|
1237
|
+
const actualIndex: number =
|
|
1238
|
+
<number>getValue('uniqueIDCollection.' + srcControlFlatData[parseInt(i.toString(), 10)].parentUniqueID + '.index', srcControl);
|
|
1239
|
+
srcControlFlatData[parseInt(i.toString(), 10)].parentItem.index = actualIndex;
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
tObj.grid.refresh();
|
|
1244
|
+
srcControl.grid.refresh();
|
|
1245
|
+
if ((<ITreeData[]>srcControl.grid.dataSource).length > 1) {
|
|
1246
|
+
srcControl.grid.refresh();
|
|
1247
|
+
if (!isNullOrUndefined(srcControl.getHeaderContent().querySelector('.e-firstrow-border'))) {
|
|
1248
|
+
srcControl.getHeaderContent().querySelector('.e-firstrow-border').remove();
|
|
1249
|
+
}
|
|
1250
|
+
if (!isNullOrUndefined(srcControl.getContent().querySelector('.e-lastrow-border'))) {
|
|
1251
|
+
srcControl.getContent().querySelector('.e-lastrow-border').remove();
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
if (isCountRequired(this.parent)) {
|
|
1256
|
+
srcControl = (<EJ2Intance>dropElement).ej2_instances[0];
|
|
1257
|
+
tObj.grid.refresh();
|
|
1258
|
+
srcControl.grid.refresh();
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
/**
|
|
1263
|
+
* Retrieves the index of the target row based on its 'aria-rowindex' attribute.
|
|
1264
|
+
*
|
|
1265
|
+
* @param {Element} targetRow - The target row element from which to retrieve the index.
|
|
1266
|
+
* @returns {number} - The index of the target row, or 0 if the targetRow is null or undefined.
|
|
1267
|
+
*/
|
|
1268
|
+
private getTargetIdx(targetRow: Element): number {
|
|
1269
|
+
return targetRow ? parseInt(targetRow.getAttribute('aria-rowindex'), 10) - 1 : 0;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
/**
|
|
1273
|
+
* Retrieves the parent data of a given record during a row drag-and-drop operation.
|
|
1274
|
+
*
|
|
1275
|
+
* @param {ITreeData} record - The record for which to retrieve the parent data.
|
|
1276
|
+
* @param {Object[]} [data] - Optional data array containing additional information related to the drop operation.
|
|
1277
|
+
* @returns {void} - This function does not return any value.
|
|
1278
|
+
*/
|
|
1279
|
+
private getParentData(record: ITreeData, data?: Object[]): void {
|
|
1280
|
+
const parentItem: ITreeData = record.parentItem; let selectedItemIndex: number = -1;
|
|
1281
|
+
if (this.parent.enableVirtualization && this.parent.selectedRowIndex !== -1) {
|
|
1282
|
+
selectedItemIndex = (this.parent.getSelectedRows()[0] as HTMLTableRowElement).rowIndex;
|
|
1283
|
+
} else if (this.parent.selectedRowIndex !== -1) {
|
|
1284
|
+
selectedItemIndex = this.parent.selectedRowIndex;
|
|
1285
|
+
}
|
|
1286
|
+
if (this.dropPosition === 'bottomSegment') {
|
|
1287
|
+
const primaryKeyField: string = this.parent.getPrimaryKeyFieldNames()[0];
|
|
1288
|
+
const rowIndex: number = selectedItemIndex === -1 ?
|
|
1289
|
+
(this.parent.grid.getRowIndexByPrimaryKey(data[0][`${primaryKeyField}`]))
|
|
1290
|
+
: this.parent.getSelectedRowIndexes()[0];
|
|
1291
|
+
const selectedRecord: ITreeData = this.parent.getCurrentViewRecords()[parseInt(rowIndex.toString(), 10)];
|
|
1292
|
+
this.droppedRecord = getParentData(this.parent, selectedRecord.parentItem.uniqueID);
|
|
1293
|
+
}
|
|
1294
|
+
if (this.dropPosition === 'middleSegment') {
|
|
1295
|
+
const level: number = (this.parent.getCurrentViewRecords()[parseInt(selectedItemIndex.toString(), 10)] as ITreeData).level;
|
|
1296
|
+
if (level === parentItem.level) {
|
|
1297
|
+
this.droppedRecord = getParentData(this.parent, parentItem.uniqueID);
|
|
1298
|
+
} else {
|
|
1299
|
+
this.getParentData(parentItem);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
/**
|
|
1305
|
+
* Handles the row drop operation for the tree grid.
|
|
1306
|
+
*
|
|
1307
|
+
* @param {RowDropEventArgs} args - The event arguments containing details about the drop operation, including the target index and data.
|
|
1308
|
+
* @param {boolean} [isByMethod=false] - Optional flag indicating if the drop operation is triggered by a method.
|
|
1309
|
+
* @returns {void} - This function does not return any value.
|
|
1310
|
+
*/
|
|
1311
|
+
private dropRows(args: RowDropEventArgs, isByMethod?: boolean): void {
|
|
1312
|
+
if (this.dropPosition !== 'Invalid' && !isRemoteData(this.parent)) {
|
|
1313
|
+
const tObj: TreeGrid = this.parent;
|
|
1314
|
+
let draggedRecord: ITreeData; let droppedRecord: ITreeData;
|
|
1315
|
+
if (isNullOrUndefined(args.dropIndex)) {
|
|
1316
|
+
const primaryKeyField: string = this.parent.getPrimaryKeyFieldNames()[0];
|
|
1317
|
+
const rowIndex: number = tObj.selectedRowIndex === -1 ?
|
|
1318
|
+
(this.parent.grid.getRowIndexByPrimaryKey(args.data[0][`${primaryKeyField}`])) - 1
|
|
1319
|
+
: tObj.getSelectedRowIndexes()[0] - 1;
|
|
1320
|
+
const record: ITreeData = (tObj.getCurrentViewRecords()[parseInt(rowIndex.toString(), 10)] as ITreeData);
|
|
1321
|
+
this.getParentData(record, args.data);
|
|
1322
|
+
} else {
|
|
1323
|
+
args.dropIndex = args.dropIndex === args.fromIndex ? this.getTargetIdx(args.target.parentElement) : args.dropIndex;
|
|
1324
|
+
if (this.parent.enableVirtualization) {
|
|
1325
|
+
const index: number = (this.parent.getRowByIndex(args.dropIndex) as HTMLTableRowElement).rowIndex;
|
|
1326
|
+
this.droppedRecord = tObj.getCurrentViewRecords()[parseInt(index.toString(), 10)];
|
|
1327
|
+
}
|
|
1328
|
+
else {
|
|
1329
|
+
if (!isNullOrUndefined(this.parent.rowDropSettings.targetID)) {
|
|
1330
|
+
const rowsObject: Row<Column>[] = this.parent.grid.getRowsObject();
|
|
1331
|
+
this.droppedRecord = rowsObject.length > 0 ? rowsObject[args.dropIndex].data : undefined;
|
|
1332
|
+
}
|
|
1333
|
+
else {
|
|
1334
|
+
this.droppedRecord = tObj.getCurrentViewRecords()[args.dropIndex];
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
let dragRecords: ITreeData[] = [];
|
|
1339
|
+
droppedRecord = this.droppedRecord;
|
|
1340
|
+
if (!args.data[0]) {
|
|
1341
|
+
dragRecords.push(args.data as ITreeData);
|
|
1342
|
+
} else {
|
|
1343
|
+
dragRecords = args.data;
|
|
1344
|
+
}
|
|
1345
|
+
this.parent[this.modifiedRecords].push(args.data[0], droppedRecord);
|
|
1346
|
+
let count: number = 0;
|
|
1347
|
+
const multiplegrid: string = this.parent.rowDropSettings.targetID;
|
|
1348
|
+
this.isMultipleGrid = multiplegrid;
|
|
1349
|
+
if (!multiplegrid) {
|
|
1350
|
+
this.ensuredropPosition(dragRecords, droppedRecord);
|
|
1351
|
+
} else {
|
|
1352
|
+
this.isaddtoBottom = multiplegrid && this.isDraggedWithChild;
|
|
1353
|
+
}
|
|
1354
|
+
const dragLength: number = dragRecords.length;
|
|
1355
|
+
if (!isNullOrUndefined(this.parent.idMapping)) {
|
|
1356
|
+
dragRecords.reverse();
|
|
1357
|
+
}
|
|
1358
|
+
for (let i: number = 0; i < dragLength; i++) {
|
|
1359
|
+
draggedRecord = dragRecords[parseInt(i.toString(), 10)];
|
|
1360
|
+
this.draggedRecord = draggedRecord;
|
|
1361
|
+
if (!this.draggedRecord.hasChildRecords) {
|
|
1362
|
+
for (const dragRecord of dragRecords) {
|
|
1363
|
+
if (!isNullOrUndefined(dragRecord.childRecords) &&
|
|
1364
|
+
dragRecord.childRecords.indexOf(this.draggedRecord) !== -1) {
|
|
1365
|
+
this.draggedRecord = undefined;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
if (!isNullOrUndefined(this.draggedRecord)) {
|
|
1370
|
+
if (this.dropPosition !== 'Invalid' && !isNullOrUndefined(this.droppedRecord)) {
|
|
1371
|
+
if (!tObj.rowDropSettings.targetID || isByMethod) {
|
|
1372
|
+
this.deleteDragRow();
|
|
1373
|
+
}
|
|
1374
|
+
if (this.draggedRecord === this.droppedRecord) {
|
|
1375
|
+
let correctIndex: number = this.getTargetIdx((<HTMLElement>args.target).offsetParent.parentElement);
|
|
1376
|
+
if (isNaN(correctIndex)) {
|
|
1377
|
+
correctIndex = this.getTargetIdx(args.target.parentElement);
|
|
1378
|
+
}
|
|
1379
|
+
args.dropIndex = correctIndex;
|
|
1380
|
+
droppedRecord = this.droppedRecord = this.parent.getCurrentViewRecords()[args.dropIndex];
|
|
1381
|
+
}
|
|
1382
|
+
if (droppedRecord.parentItem || this.dropPosition === 'middleSegment') {
|
|
1383
|
+
const parentRecords: ITreeData[] = tObj.parentData;
|
|
1384
|
+
const newParentIndex: number = parentRecords.indexOf(this.draggedRecord);
|
|
1385
|
+
if (newParentIndex !== -1) {
|
|
1386
|
+
parentRecords.splice(newParentIndex, 1);
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
const recordIndex1: number = this.treeGridData.indexOf(droppedRecord);
|
|
1390
|
+
this.dropAtTop(recordIndex1);
|
|
1391
|
+
if (this.dropPosition === 'bottomSegment') {
|
|
1392
|
+
if (!droppedRecord.hasChildRecords) {
|
|
1393
|
+
if (this.parent.parentIdMapping) {
|
|
1394
|
+
this.treeData.splice(recordIndex1 + 1, 0, this.draggedRecord.taskData);
|
|
1395
|
+
}
|
|
1396
|
+
this.treeGridData.splice(recordIndex1 + 1, 0, this.draggedRecord);
|
|
1397
|
+
} else {
|
|
1398
|
+
count = this.getChildCount(droppedRecord, 0);
|
|
1399
|
+
if (this.parent.parentIdMapping) {
|
|
1400
|
+
this.treeData.splice(recordIndex1 + count + 1, 0, this.draggedRecord.taskData);
|
|
1401
|
+
}
|
|
1402
|
+
this.treeGridData.splice(recordIndex1 + count + 1, 0, this.draggedRecord);
|
|
1403
|
+
}
|
|
1404
|
+
if (isNullOrUndefined(droppedRecord.parentItem)) {
|
|
1405
|
+
delete draggedRecord.parentItem;
|
|
1406
|
+
delete draggedRecord.parentUniqueID;
|
|
1407
|
+
draggedRecord.level = 0;
|
|
1408
|
+
if (this.parent.parentIdMapping) {
|
|
1409
|
+
draggedRecord[this.parent.parentIdMapping] = null;
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
if (droppedRecord.parentItem) {
|
|
1413
|
+
const rec: ITreeData[] = this.getChildrecordsByParentID(droppedRecord.parentUniqueID);
|
|
1414
|
+
const childRecords: ITreeData[] = rec[0].childRecords;
|
|
1415
|
+
const droppedRecordIndex: number = childRecords.indexOf(droppedRecord) + 1;
|
|
1416
|
+
childRecords.splice(droppedRecordIndex, 0, draggedRecord);
|
|
1417
|
+
draggedRecord.parentItem = droppedRecord.parentItem;
|
|
1418
|
+
draggedRecord.parentUniqueID = droppedRecord.parentUniqueID;
|
|
1419
|
+
draggedRecord.level = droppedRecord.level;
|
|
1420
|
+
if (this.parent.parentIdMapping) {
|
|
1421
|
+
draggedRecord[this.parent.parentIdMapping] = droppedRecord[this.parent.parentIdMapping];
|
|
1422
|
+
draggedRecord.parentItem = droppedRecord.parentItem;
|
|
1423
|
+
draggedRecord.level = droppedRecord.level;
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
if (draggedRecord.hasChildRecords) {
|
|
1427
|
+
const level: number = 1;
|
|
1428
|
+
this.updateChildRecordLevel(draggedRecord, level);
|
|
1429
|
+
this.updateChildRecord(draggedRecord, recordIndex1 + count + 1);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
this.dropMiddle(recordIndex1);
|
|
1433
|
+
}
|
|
1434
|
+
if (isNullOrUndefined(draggedRecord.parentItem)) {
|
|
1435
|
+
const parentRecords: ITreeData[] = tObj.parentData;
|
|
1436
|
+
const newParentIndex: number = parentRecords.indexOf(this.droppedRecord);
|
|
1437
|
+
let nonRepeat: number = 0;
|
|
1438
|
+
parentRecords.filter((e: ITreeData) => {
|
|
1439
|
+
if (draggedRecord.uniqueID === e.uniqueID) {
|
|
1440
|
+
nonRepeat++;
|
|
1441
|
+
}
|
|
1442
|
+
});
|
|
1443
|
+
if (this.dropPosition === 'bottomSegment' && nonRepeat === 0) {
|
|
1444
|
+
parentRecords.splice(newParentIndex + 1, 0, draggedRecord);
|
|
1445
|
+
} else if (this.dropPosition === 'topSegment' && nonRepeat === 0) {
|
|
1446
|
+
parentRecords.splice(newParentIndex, 0, draggedRecord);
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
tObj.rowDragAndDropModule.refreshGridDataSource();
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
/**
|
|
1456
|
+
* Handles the logic for inserting a dragged record into the middle of a parent record's child records.
|
|
1457
|
+
*
|
|
1458
|
+
* @param {number} recordIndex - The index at which to insert the dragged record relative to the parent record's child records.
|
|
1459
|
+
* @returns {void} - This function does not return any value.
|
|
1460
|
+
*/
|
|
1461
|
+
private dropMiddle(recordIndex: number): void {
|
|
1462
|
+
const tObj: TreeGrid = this.parent;
|
|
1463
|
+
const childRecords: ITreeData[] = findChildrenRecords(this.droppedRecord);
|
|
1464
|
+
const childRecordsLength: number = (isNullOrUndefined(childRecords) ||
|
|
1465
|
+
childRecords.length === 0) ? recordIndex + 1 :
|
|
1466
|
+
childRecords.length + recordIndex + 1;
|
|
1467
|
+
if (this.dropPosition === 'middleSegment') {
|
|
1468
|
+
if (tObj.parentIdMapping) {
|
|
1469
|
+
this.treeData.splice(childRecordsLength, 0, this.draggedRecord.taskData);
|
|
1470
|
+
this.treeGridData.splice(childRecordsLength, 0, this.draggedRecord);
|
|
1471
|
+
} else {
|
|
1472
|
+
this.treeGridData.splice(childRecordsLength, 0, this.draggedRecord);
|
|
1473
|
+
}
|
|
1474
|
+
this.recordLevel();
|
|
1475
|
+
if (this.draggedRecord.hasChildRecords) {
|
|
1476
|
+
this.updateChildRecord(this.draggedRecord, childRecordsLength);
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
/**
|
|
1482
|
+
* Handles the logic for inserting a dragged record at the top of a parent record's child records.
|
|
1483
|
+
*
|
|
1484
|
+
* @param {number} recordIndex1 - The index at which to insert the dragged record in the tree grid data.
|
|
1485
|
+
* @returns {void} - This function does not return any value.
|
|
1486
|
+
*/
|
|
1487
|
+
private dropAtTop(recordIndex1: number): void {
|
|
1488
|
+
const tObj: TreeGrid = this.parent;
|
|
1489
|
+
if (this.dropPosition === 'topSegment') {
|
|
1490
|
+
if (tObj.parentIdMapping) {
|
|
1491
|
+
this.treeData.splice(recordIndex1, 0, this.draggedRecord.taskData);
|
|
1492
|
+
}
|
|
1493
|
+
const targetRecord: ITreeData = this.treeGridData[parseInt(recordIndex1.toString(), 10)];
|
|
1494
|
+
this.draggedRecord.parentItem = targetRecord.parentItem;
|
|
1495
|
+
this.draggedRecord.parentUniqueID = targetRecord.parentUniqueID;
|
|
1496
|
+
this.draggedRecord.level = targetRecord.level;
|
|
1497
|
+
// Insert dragged record into the grid data
|
|
1498
|
+
this.treeGridData.splice(parseInt(recordIndex1.toString(), 10), 0, this.draggedRecord);
|
|
1499
|
+
if (this.draggedRecord.hasChildRecords) {
|
|
1500
|
+
const level: number = 1;
|
|
1501
|
+
this.updateChildRecord(this.draggedRecord, recordIndex1);
|
|
1502
|
+
this.updateChildRecordLevel(this.draggedRecord, level);
|
|
1503
|
+
}
|
|
1504
|
+
if (this.droppedRecord.parentItem) {
|
|
1505
|
+
const rec: ITreeData[] = this.getChildrecordsByParentID(this.droppedRecord.parentUniqueID);
|
|
1506
|
+
const childRecords: ITreeData[] = rec[0].childRecords;
|
|
1507
|
+
const droppedRecordIndex: number = childRecords.indexOf(this.droppedRecord);
|
|
1508
|
+
// Insert the dragged record into the child records at the appropriate position
|
|
1509
|
+
childRecords.splice(droppedRecordIndex, 0, this.draggedRecord);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
/**
|
|
1515
|
+
* Updates the level and hierarchy of the dragged record based on the drop position.
|
|
1516
|
+
*
|
|
1517
|
+
* @returns {void} - This function does not return any value.
|
|
1518
|
+
*/
|
|
1519
|
+
private recordLevel(): void {
|
|
1520
|
+
const tObj: TreeGrid = this.parent;
|
|
1521
|
+
const draggedRecord: ITreeData = this.draggedRecord;
|
|
1522
|
+
const droppedRecord: ITreeData = this.droppedRecord;
|
|
1523
|
+
const childItem: string = tObj.childMapping;
|
|
1524
|
+
if (!droppedRecord.hasChildRecords) {
|
|
1525
|
+
droppedRecord.hasChildRecords = true;
|
|
1526
|
+
droppedRecord.hasFilteredChildRecords = true;
|
|
1527
|
+
if (isNullOrUndefined(droppedRecord.childRecords) || droppedRecord.childRecords.length === 0) {
|
|
1528
|
+
droppedRecord.childRecords = [];
|
|
1529
|
+
if (!tObj.parentIdMapping && isNullOrUndefined(droppedRecord.taskData[`${childItem}`])) {
|
|
1530
|
+
droppedRecord.taskData[`${childItem}`] = [];
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
if (this.dropPosition === 'middleSegment') {
|
|
1535
|
+
const parentItem: ITreeData = extend({}, droppedRecord);
|
|
1536
|
+
delete parentItem.childRecords;
|
|
1537
|
+
draggedRecord.parentItem = parentItem;
|
|
1538
|
+
draggedRecord.parentUniqueID = droppedRecord.uniqueID;
|
|
1539
|
+
droppedRecord.childRecords.splice(droppedRecord.childRecords.length, 0, draggedRecord);
|
|
1540
|
+
setValue('uniqueIDCollection.' + draggedRecord.uniqueID, draggedRecord, tObj);
|
|
1541
|
+
const isSelfReference: string = 'isSelfReference';
|
|
1542
|
+
if (tObj[`${isSelfReference}`]) {
|
|
1543
|
+
droppedRecord[tObj.childMapping] = [];
|
|
1544
|
+
droppedRecord[tObj.childMapping].splice(droppedRecord[tObj.childMapping].length, 0, draggedRecord);
|
|
1545
|
+
}
|
|
1546
|
+
if (!isNullOrUndefined(draggedRecord) && !tObj.parentIdMapping && !isNullOrUndefined(droppedRecord.taskData[`${childItem}`])) {
|
|
1547
|
+
droppedRecord.taskData[tObj.childMapping].splice(droppedRecord.childRecords.length, 0, draggedRecord.taskData);
|
|
1548
|
+
}
|
|
1549
|
+
if (!draggedRecord.hasChildRecords) {
|
|
1550
|
+
draggedRecord.level = droppedRecord.level + 1;
|
|
1551
|
+
} else {
|
|
1552
|
+
const level: number = 1;
|
|
1553
|
+
draggedRecord.level = droppedRecord.level + 1;
|
|
1554
|
+
this.updateChildRecordLevel(draggedRecord, level);
|
|
1555
|
+
}
|
|
1556
|
+
droppedRecord.expanded = true;
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
/**
|
|
1561
|
+
* Deletes the currently dragged row from the TreeGrid.
|
|
1562
|
+
*
|
|
1563
|
+
* @returns {void} - This function does not return any value.
|
|
1564
|
+
*/
|
|
1565
|
+
private deleteDragRow(): void {
|
|
1566
|
+
if (this.parent.dataSource instanceof DataManager && isOffline(this.parent)) {
|
|
1567
|
+
this.treeGridData = (<DataManager>this.parent.grid.dataSource).dataSource.json;
|
|
1568
|
+
this.treeData = (<DataManager>this.parent.dataSource).dataSource.json;
|
|
1569
|
+
} else {
|
|
1570
|
+
this.treeGridData = this.parent.grid.dataSource as ITreeData[];
|
|
1571
|
+
this.treeData = this.parent.dataSource as ITreeData[];
|
|
1572
|
+
}
|
|
1573
|
+
const deletedRow: ITreeData = getParentData(this.parent, this.draggedRecord.uniqueID);
|
|
1574
|
+
if (!isNullOrUndefined(deletedRow.childRecords) && deletedRow.childRecords.length) {
|
|
1575
|
+
deletedRow.hasChildRecords = true;
|
|
1576
|
+
}
|
|
1577
|
+
this.removeRecords(deletedRow);
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
/**
|
|
1581
|
+
* Updates the child records of a specified parent record in the TreeGrid.
|
|
1582
|
+
*
|
|
1583
|
+
* @param {ITreeData} record - The parent record whose child records will be updated.
|
|
1584
|
+
* @param {number} count - The initial count to keep track of record positioning.
|
|
1585
|
+
* @returns {number} - The updated count after processing all child records.
|
|
1586
|
+
*/
|
|
1587
|
+
private updateChildRecord(record: ITreeData, count: number): number {
|
|
1588
|
+
let currentRecord: ITreeData;
|
|
1589
|
+
const tObj: TreeGrid = this.parent;
|
|
1590
|
+
let length: number = 0;
|
|
1591
|
+
if (!record.hasChildRecords) {
|
|
1592
|
+
return 0;
|
|
1593
|
+
}
|
|
1594
|
+
length = record.childRecords.length;
|
|
1595
|
+
for (let i: number = 0; i < length; i++) {
|
|
1596
|
+
if (!this.isMultipleGrid) {
|
|
1597
|
+
currentRecord = getValue('uniqueIDCollection.' + record.childRecords[parseInt(i.toString(), 10)].uniqueID, tObj);
|
|
1598
|
+
} else {
|
|
1599
|
+
currentRecord = record.childRecords[parseInt(i.toString(), 10)];
|
|
1600
|
+
}
|
|
1601
|
+
count++;
|
|
1602
|
+
tObj.flatData.splice(count, 0, currentRecord);
|
|
1603
|
+
setValue('uniqueIDCollection.' + currentRecord.uniqueID, currentRecord, this.parent);
|
|
1604
|
+
if (tObj.parentIdMapping) {
|
|
1605
|
+
this.treeData.splice(count, 0, currentRecord.taskData);
|
|
1606
|
+
}
|
|
1607
|
+
if (currentRecord.hasChildRecords) {
|
|
1608
|
+
count = this.updateChildRecord(currentRecord, count);
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
return count;
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
/**
|
|
1615
|
+
* Updates the level of child records for a specified parent record in the TreeGrid.
|
|
1616
|
+
*
|
|
1617
|
+
* @param {ITreeData} record - The parent record whose child records' levels will be updated.
|
|
1618
|
+
* @param {number} level - The current level of the parent record.
|
|
1619
|
+
* @returns {number} - The updated level after processing all child records.
|
|
1620
|
+
*/
|
|
1621
|
+
private updateChildRecordLevel(record: ITreeData, level: number): number {
|
|
1622
|
+
let length: number = 0;
|
|
1623
|
+
let currentRecord: ITreeData;
|
|
1624
|
+
level++;
|
|
1625
|
+
if (!record.hasChildRecords) {
|
|
1626
|
+
return 0;
|
|
1627
|
+
}
|
|
1628
|
+
length = record.childRecords.length;
|
|
1629
|
+
for (let i: number = 0; i < length; i++) {
|
|
1630
|
+
if (!this.isMultipleGrid) {
|
|
1631
|
+
currentRecord = getValue('uniqueIDCollection.' + record.childRecords[parseInt(i.toString(), 10)].uniqueID, this.parent);
|
|
1632
|
+
} else {
|
|
1633
|
+
currentRecord = record.childRecords[parseInt(i.toString(), 10)];
|
|
1634
|
+
}
|
|
1635
|
+
let parentData: ITreeData;
|
|
1636
|
+
if (record.parentItem) {
|
|
1637
|
+
parentData = getParentData(this.parent, record.parentItem.uniqueID);
|
|
1638
|
+
}
|
|
1639
|
+
if (isNullOrUndefined(parentData) && !isNullOrUndefined(record.parentItem)) { parentData = record.parentItem; }
|
|
1640
|
+
currentRecord.level = record.parentItem ? parentData.level + level : record.level + 1;
|
|
1641
|
+
if (currentRecord.hasChildRecords) {
|
|
1642
|
+
level--;
|
|
1643
|
+
level = this.updateChildRecordLevel(currentRecord, level);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
return level;
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
/**
|
|
1650
|
+
* Removes specified records from the TreeGrid data source.
|
|
1651
|
+
*
|
|
1652
|
+
* @param {ITreeData} record - The record to be removed, including any child records if applicable.
|
|
1653
|
+
* @returns {void} - This method does not return a value.
|
|
1654
|
+
*/
|
|
1655
|
+
private removeRecords(record: ITreeData): void {
|
|
1656
|
+
const tObj: TreeGrid = this.parent;
|
|
1657
|
+
let dataSource: Object;
|
|
1658
|
+
if (this.parent.dataSource instanceof DataManager && isOffline(this.parent)) {
|
|
1659
|
+
dataSource = (<DataManager>this.parent.dataSource).dataSource.json;
|
|
1660
|
+
} else {
|
|
1661
|
+
dataSource = this.parent.dataSource;
|
|
1662
|
+
}
|
|
1663
|
+
const deletedRow: ITreeData = record;
|
|
1664
|
+
const isSelfReference: boolean = !isNullOrUndefined(tObj.parentIdMapping);
|
|
1665
|
+
const flatParentData: ITreeData = (this.getChildrecordsByParentID(deletedRow.parentUniqueID) as ITreeData)[0];
|
|
1666
|
+
if (deletedRow) {
|
|
1667
|
+
if (deletedRow.parentItem) {
|
|
1668
|
+
const childRecords: ITreeData[] = flatParentData ? flatParentData.childRecords : [];
|
|
1669
|
+
let childIndex: number = 0;
|
|
1670
|
+
if (childRecords && childRecords.length > 0) {
|
|
1671
|
+
childIndex = childRecords.indexOf(deletedRow);
|
|
1672
|
+
flatParentData.childRecords.splice(childIndex, 1);
|
|
1673
|
+
if (!this.parent.parentIdMapping || tObj.enableImmutableMode) {
|
|
1674
|
+
editAction({ value: deletedRow, action: 'delete' }, this.parent,
|
|
1675
|
+
isSelfReference, deletedRow.index, deletedRow.index);
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
if (tObj.parentIdMapping) {
|
|
1680
|
+
if (deletedRow.hasChildRecords && deletedRow.childRecords.length > 0) {
|
|
1681
|
+
this.removeChildItem(deletedRow);
|
|
1682
|
+
}
|
|
1683
|
+
const treeGridData: ITreeData[] = dataSource as ITreeData[];
|
|
1684
|
+
const idx: number = treeGridData.findIndex((data: ITreeData) => {
|
|
1685
|
+
return data[this.parent.idMapping] === deletedRow.taskData[this.parent.idMapping];
|
|
1686
|
+
});
|
|
1687
|
+
const idz: number = this.treeGridData.findIndex((data: ITreeData) => {
|
|
1688
|
+
return data[this.parent.idMapping] === deletedRow.taskData[this.parent.idMapping];
|
|
1689
|
+
});
|
|
1690
|
+
if (idx !== -1 && !isNullOrUndefined(idx)) {
|
|
1691
|
+
(dataSource as ITreeData[]).splice(idx, 1);
|
|
1692
|
+
}
|
|
1693
|
+
if (idz !== -1 && !isNullOrUndefined(idz)) {
|
|
1694
|
+
this.treeGridData.splice(idz, 1);
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
let recordIndex: number = this.treeGridData.indexOf(deletedRow);
|
|
1698
|
+
if (!tObj.parentIdMapping) {
|
|
1699
|
+
const parentIndex: number = this.parent.parentData.indexOf(deletedRow);
|
|
1700
|
+
if (parentIndex !== -1) {
|
|
1701
|
+
tObj.parentData.splice(parentIndex, 1);
|
|
1702
|
+
(dataSource as ITreeData[]).splice(parentIndex, 1);
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
if (recordIndex === -1 && !tObj.parentIdMapping) {
|
|
1706
|
+
const primaryKeyField: string = tObj.getPrimaryKeyFieldNames()[0];
|
|
1707
|
+
for (let j: number = 0; j < this.treeGridData.length; j++) {
|
|
1708
|
+
if (this.treeGridData[parseInt(j.toString(), 10)][`${primaryKeyField}`] === deletedRow[`${primaryKeyField}`]) {
|
|
1709
|
+
recordIndex = j;
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
if (!tObj.parentIdMapping) {
|
|
1714
|
+
const deletedRecordCount: number = this.getChildCount(deletedRow, 0);
|
|
1715
|
+
this.treeGridData.splice(recordIndex, deletedRecordCount + 1);
|
|
1716
|
+
}
|
|
1717
|
+
if (deletedRow.parentItem && flatParentData && flatParentData.childRecords && !flatParentData.childRecords.length) {
|
|
1718
|
+
flatParentData.expanded = false;
|
|
1719
|
+
flatParentData.hasChildRecords = false;
|
|
1720
|
+
flatParentData.hasFilteredChildRecords = false;
|
|
1721
|
+
}
|
|
1722
|
+
if (this.parent[this.modifiedRecords].indexOf(flatParentData) === -1 && !isNullOrUndefined(flatParentData)) {
|
|
1723
|
+
this.parent[this.modifiedRecords].push(flatParentData);
|
|
1724
|
+
}
|
|
1725
|
+
if (!isNullOrUndefined(flatParentData)) {
|
|
1726
|
+
this.updateModifiedRecords(flatParentData);
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
/**
|
|
1732
|
+
* Updates the records in the TreeGrid data source that have been modified.
|
|
1733
|
+
*
|
|
1734
|
+
* @param {ITreeData} record - The record to update, along with its parent records if applicable.
|
|
1735
|
+
* @returns {void} - This method does not return a value.
|
|
1736
|
+
*/
|
|
1737
|
+
private updateModifiedRecords(record: ITreeData): void {
|
|
1738
|
+
const parentData: Object = getParentData(this.parent, record.parentUniqueID);
|
|
1739
|
+
if (!isNullOrUndefined(parentData)) {
|
|
1740
|
+
this.parent[this.modifiedRecords].push(parentData);
|
|
1741
|
+
this.updateModifiedRecords(parentData);
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
/**
|
|
1746
|
+
* Recursively removes child records from the specified record and updates the data source.
|
|
1747
|
+
*
|
|
1748
|
+
* @param {ITreeData} record - The parent record whose child records are to be removed.
|
|
1749
|
+
* @returns {void} - This method does not return a value.
|
|
1750
|
+
*/
|
|
1751
|
+
private removeChildItem(record: ITreeData): void {
|
|
1752
|
+
let currentRecord: ITreeData;
|
|
1753
|
+
let idx: number;
|
|
1754
|
+
let idz: number;
|
|
1755
|
+
let dataSource: Object;
|
|
1756
|
+
if (this.parent.dataSource instanceof DataManager && isOffline(this.parent)) {
|
|
1757
|
+
dataSource = (<DataManager>this.parent.dataSource).dataSource.json;
|
|
1758
|
+
} else {
|
|
1759
|
+
dataSource = this.parent.dataSource;
|
|
1760
|
+
}
|
|
1761
|
+
for (let i: number = 0; i < record.childRecords.length; i++) {
|
|
1762
|
+
currentRecord = record.childRecords[parseInt(i.toString(), 10)];
|
|
1763
|
+
if (!isNullOrUndefined(currentRecord.childRecords) && currentRecord.childRecords.length) {
|
|
1764
|
+
currentRecord.hasChildRecords = true;
|
|
1765
|
+
}
|
|
1766
|
+
let treeGridData: Object;
|
|
1767
|
+
if (this.parent.dataSource instanceof DataManager && isOffline(this.parent)) {
|
|
1768
|
+
treeGridData = (<DataManager>this.parent.dataSource).dataSource.json;
|
|
1769
|
+
} else {
|
|
1770
|
+
treeGridData = this.parent.dataSource;
|
|
1771
|
+
}
|
|
1772
|
+
for (let i: number = 0; i < (<ITreeData[]>treeGridData).length; i++) {
|
|
1773
|
+
if (treeGridData[parseInt(i.toString(), 10)][this.parent.idMapping] === currentRecord.taskData[this.parent.idMapping]) {
|
|
1774
|
+
idx = i;
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
for (let i: number = 0; i < this.treeGridData.length; i++) {
|
|
1778
|
+
if (this.treeGridData[parseInt(i.toString(), 10)][this.parent.idMapping]
|
|
1779
|
+
=== currentRecord.taskData[this.parent.idMapping]) {
|
|
1780
|
+
idz = i;
|
|
1781
|
+
break;
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
if (idx !== -1 && !isNullOrUndefined(idx)) {
|
|
1785
|
+
(dataSource as ITreeData[]).splice(idx, 1);
|
|
1786
|
+
}
|
|
1787
|
+
if (idz !== -1 && !isNullOrUndefined(idz)) {
|
|
1788
|
+
this.treeGridData.splice(idz, 1);
|
|
1789
|
+
}
|
|
1790
|
+
if (currentRecord.hasChildRecords) {
|
|
1791
|
+
this.removeChildItem(currentRecord);
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
/**
|
|
1797
|
+
* Retrieves the count of child records associated with the specified parent record.
|
|
1798
|
+
*
|
|
1799
|
+
* @param {ITreeData} record - The parent record for which child count is to be calculated.
|
|
1800
|
+
* @param {number} count - The initial count to start with, usually passed as 0.
|
|
1801
|
+
* @returns {number} - The total count of child records.
|
|
1802
|
+
*/
|
|
1803
|
+
private getChildCount(record: ITreeData, count: number): number {
|
|
1804
|
+
let currentRecord: ITreeData;
|
|
1805
|
+
if (!record.hasChildRecords) {
|
|
1806
|
+
return 0;
|
|
1807
|
+
}
|
|
1808
|
+
for (let i: number = 0; i < record.childRecords.length; i++) {
|
|
1809
|
+
currentRecord = record.childRecords[parseInt(i.toString(), 10)];
|
|
1810
|
+
count++;
|
|
1811
|
+
if (currentRecord.hasChildRecords) {
|
|
1812
|
+
count = this.getChildCount(currentRecord, count);
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
return count;
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
/**
|
|
1819
|
+
* Ensures the validity of the drop position for the dragged records by verifying the hierarchy and position constraints.
|
|
1820
|
+
* If the current record is found in the dragged records' children, sets the drop position to 'Invalid'.
|
|
1821
|
+
*
|
|
1822
|
+
* @param {ITreeData[]} draggedRecords - The array of dragged records being verified.
|
|
1823
|
+
* @param {ITreeData} currentRecord - The current record to check against dragged records.
|
|
1824
|
+
* @returns {void} - This function does not return a value.
|
|
1825
|
+
*/
|
|
1826
|
+
private ensuredropPosition(draggedRecords: ITreeData[], currentRecord: ITreeData): void {
|
|
1827
|
+
draggedRecords.filter((e: ITreeData) => {
|
|
1828
|
+
if (e.hasChildRecords && !isNullOrUndefined(e.childRecords)) {
|
|
1829
|
+
const valid: number = e.childRecords.indexOf(currentRecord);
|
|
1830
|
+
if (valid === -1) {
|
|
1831
|
+
this.ensuredropPosition(e.childRecords, currentRecord);
|
|
1832
|
+
} else {
|
|
1833
|
+
this.dropPosition = 'Invalid';
|
|
1834
|
+
this.addErrorElem();
|
|
1835
|
+
this.canDrop = false;
|
|
1836
|
+
if (isNullOrUndefined(this.parent.rowDropSettings.targetID)) {
|
|
1837
|
+
this.removetopOrBottomBorder();
|
|
1838
|
+
this.removeChildBorder();
|
|
1839
|
+
}
|
|
1840
|
+
return;
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
});
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
private isDuplicateData(currentData: any): boolean {
|
|
1847
|
+
const primaryKeys: string[] = this.parent.getPrimaryKeyFieldNames();
|
|
1848
|
+
if (primaryKeys.length === 0) {
|
|
1849
|
+
return false;
|
|
1850
|
+
}
|
|
1851
|
+
return this.parent.flatData.some((data: any) =>
|
|
1852
|
+
// eslint-disable-next-line
|
|
1853
|
+
primaryKeys.every((key: string) => data[key] === currentData[key])
|
|
1854
|
+
);
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
/**
|
|
1858
|
+
* Cleans up resources, event listeners, and DOM elements when the TreeGrid component is destroyed.
|
|
1859
|
+
*
|
|
1860
|
+
* @returns {void}
|
|
1861
|
+
*/
|
|
1862
|
+
public destroy(): void {
|
|
1863
|
+
this.removeEventListener();
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
/**
|
|
1867
|
+
* @hidden
|
|
1868
|
+
* @returns {void}
|
|
1869
|
+
*/
|
|
1870
|
+
public removeEventListener(): void {
|
|
1871
|
+
if (this.parent.isDestroyed) { return; }
|
|
1872
|
+
this.parent.off(events.rowdraging, this.Rowdraging);
|
|
1873
|
+
this.parent.off(events.rowDropped, this.rowDropped);
|
|
1874
|
+
this.parent.off(events.rowsAdd, this.rowsAdded);
|
|
1875
|
+
this.parent.off(events.rowsRemove, this.rowsRemoved);
|
|
1876
|
+
}
|
|
1877
|
+
/**
|
|
1878
|
+
* hidden
|
|
1879
|
+
*/
|
|
1880
|
+
/**
|
|
1881
|
+
* For internal use only - Get the module name.
|
|
1882
|
+
*
|
|
1883
|
+
* @private
|
|
1884
|
+
* @returns {string} Returns RowDragAndDrop module name
|
|
1885
|
+
*/
|
|
1886
|
+
private getModuleName(): string {
|
|
1887
|
+
return 'rowDragAndDrop';
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
|
|
1892
|
+
interface PositionOffSet {
|
|
1893
|
+
left: number;
|
|
1894
|
+
top: number;
|
|
1895
|
+
}
|
|
1896
|
+
|