@syncfusion/ej2-treegrid
Version:
Essential JS 2 TreeGrid Component
996 lines • 93.7 kB
JavaScript
import { Grid, RowDD as GridDragDrop, parentsUntil } from '@syncfusion/ej2-grids';
import { getObject, Scroll } from '@syncfusion/ej2-grids';
import { closest, isNullOrUndefined, setValue, extend, getValue, removeClass, addClass, setStyleAttribute } from '@syncfusion/ej2-base';
import { DataManager } from '@syncfusion/ej2-data';
import * as events from '../base/constant';
import { editAction } from './crud-actions';
import { getParentData, findChildrenRecords, isRemoteData, isOffline, isCountRequired } from '../utils';
/**
* TreeGrid RowDragAndDrop module
*
* @hidden
*/
var RowDD = /** @class */ (function () {
/**
* Constructor for render module
*
* @param {TreeGrid} parent - Tree Grid instance
*/
function RowDD(parent) {
/** @hidden
* Indicates whether a row can be dropped into the current target position during a drag-and-drop operation.
*/
this.canDrop = true;
/** @hidden
* Indicates whether the current drag operation includes child records of the dragged item.
*/
this.isDraggedWithChild = false;
/** @hidden
* Indicates whether multiple TreeGrid instances are being managed or displayed.
*/
this.modifiedRecords = 'modifiedRecords';
/** @hidden
* Represents the currently selected item in the TreeGrid.
*/
this.selectedRecords = 'selectedRecords';
/** @hidden
* Holds an array of currently selected records in the TreeGrid.
*/
this.selectedRows = 'selectedRows';
/** @hidden
* Indicates whether there is a droppable item in the TreeGrid.
*/
this.hasDropItem = true;
/** @hidden
* Indicates whether the item is being added to the bottom of the TreeGrid.
*/
this.isaddtoBottom = false;
Grid.Inject(GridDragDrop);
this.parent = parent;
this.addEventListener();
}
/**
* Retrieves child records for a specified parent ID in the TreeGrid.
*
* @param {string} id - The unique ID of the parent record for which to retrieve child records.
* @returns {ITreeData[]} An array of child records corresponding to the specified parent ID.
*/
RowDD.prototype.getChildrecordsByParentID = function (id) {
var treeGridDataSource;
if (this.parent.dataSource instanceof DataManager && isOffline(this.parent)) {
treeGridDataSource = this.parent.grid.dataSource.dataSource.json;
}
else {
treeGridDataSource = this.parent.grid.dataSource;
}
var record = treeGridDataSource.filter(function (e) {
return e.uniqueID === id;
});
return record;
};
/**
* @hidden
* @returns {void}
*/
RowDD.prototype.addEventListener = function () {
this.parent.on(events.rowdraging, this.Rowdraging, this);
this.parent.on(events.rowDropped, this.rowDropped, this);
this.parent.on(events.rowsAdd, this.rowsAdded, this);
this.parent.on(events.rowsRemove, this.rowsRemoved, this);
};
/**
* Reorder the rows based on given indexes and position
*
* @returns {void}
* @param {number[]} fromIndexes - source indexes of rows to be re-ordered
* @param {number} toIndex - Destination row index
* @param {string} position - Drop position as above or below or child
*/
RowDD.prototype.reorderRows = function (fromIndexes, toIndex, position) {
var tObj = this.parent;
if (fromIndexes[0] === toIndex || ['above', 'below', 'child'].indexOf(position) === -1) {
return;
}
var action = 'action';
var dropPosition = 'dropPosition';
if (fromIndexes[0] !== toIndex && ['above', 'below', 'child'].indexOf(position) !== -1) {
if (position === 'above') {
this.dropPosition = 'topSegment';
}
if (position === 'below') {
this.dropPosition = 'bottomSegment';
}
if (position === 'child') {
this.dropPosition = 'middleSegment';
}
this.parent["" + dropPosition] = this.dropPosition;
var data = [];
for (var i = 0; i < fromIndexes.length; i++) {
var index = this.parent.getRowByIndex(fromIndexes[parseInt(i.toString(), 10)]).rowIndex;
data[parseInt(i.toString(), 10)] = this.parent.getCurrentViewRecords()[parseInt(index.toString(), 10)];
}
var isByMethod = true;
var args = {
data: data,
dropIndex: toIndex
};
if (!isCountRequired(this.parent)) {
this.dropRows(args, isByMethod);
}
//this.refreshGridDataSource();
if (tObj.isLocalData) {
tObj.flatData = this.orderToIndex(tObj.flatData);
}
if (this.parent["" + action] === 'outdenting') {
if (!isNullOrUndefined(data[0].parentItem)) {
data[0].level = data[0].parentItem.level + 1;
}
}
this.parent.grid.refresh();
if (this.parent.enableImmutableMode && this.dropPosition === 'middleSegment') {
var index = this.parent.allowRowDragAndDrop
? this.parent.treeColumnIndex + 1
: (this.parent["" + action] === 'indenting' ? this.parent.treeColumnIndex : undefined);
var row = this.parent.getRows()[fromIndexes[0]];
var dropData = args.data[0];
var totalRecord = [];
var rows = [];
totalRecord.push(dropData);
rows.push(row);
var parentUniqueID = 'parentUniqueID';
var parentData = getParentData(this.parent, args.data[0]["" + parentUniqueID]);
var parentrow = this.parent.getRows()[parseInt(toIndex.toString(), 10)];
totalRecord.push(parentData);
rows.push(parentrow);
this.updateRowAndCellElements(totalRecord, rows, index);
}
if (this.parent.enableImmutableMode && this.parent["" + action] === 'outdenting') {
var index = this.parent.allowRowDragAndDrop
? this.parent.treeColumnIndex + 1
: (this.parent["" + action] === 'outdenting' ? this.parent.treeColumnIndex : undefined);
var record = args.data[0];
var row = this.parent.getRows()[fromIndexes[0]];
var totalRecord = [];
var rows = [];
totalRecord.push(record);
rows.push(row);
this.updateRowAndCellElements(totalRecord, rows, index);
}
}
};
/**
* Updates the rows and cells
*
* @param {Object[]} records - Updates the given records
* @param {HTMLTableRowElement[]} rows - Updates the given rows
* @param {number} index - Updates the given cell index
* @returns {void}
*/
RowDD.prototype.updateRowAndCellElements = function (records, rows, index) {
for (var i = 0; i < records.length; i++) {
this.parent.renderModule.cellRender({
data: records[parseInt(i.toString(), 10)], cell: rows[parseInt(i.toString(), 10)].cells[parseInt(index.toString(), 10)],
column: this.parent.grid.getColumns()[this.parent.treeColumnIndex],
requestType: 'rowDragAndDrop'
});
if (this.parent['action'] === 'indenting' || this.parent['action'] === 'outdenting') {
this.parent.renderModule.RowModifier({
data: records[parseInt(i.toString(), 10)], row: rows[parseInt(i.toString(), 10)]
});
}
}
};
/**
* Performs indent or outdent actions on selected records in the TreeGrid.
*
* @param {ITreeData} [record] - The record to be indented or outdented. If undefined, the method operates on the currently selected record.
* @param {string} [request] - The action to perform, either 'indent' or 'outdent'.
* @returns {void}
*/
RowDD.prototype.indentOutdentAction = function (record, request) {
var tObj = this.parent;
var action = 'action';
var droppedIndex = 'dropIndex';
var selectedItemIndex = -1;
if (isNullOrUndefined(record) && this.parent.selectedRowIndex === -1) {
return;
}
else {
if (this.parent.enableVirtualization && this.parent.selectedRowIndex !== -1) {
selectedItemIndex = this.parent.getSelectedRows()[0].rowIndex;
}
else if (this.parent.selectedRowIndex !== -1) {
selectedItemIndex = this.parent.selectedRowIndex;
}
this.selectedItem = isNullOrUndefined(record) ?
tObj.getCurrentViewRecords()[parseInt(selectedItemIndex.toString(), 10)] : record;
var primaryKeyField = this.parent.getPrimaryKeyFieldNames()[0];
var rowIndex = this.parent.grid.getRowIndexByPrimaryKey(this.selectedItem["" + primaryKeyField]);
this.selectedRow = this.parent[this.selectedRows] = selectedItemIndex !== -1 ?
this.parent.getSelectedRows()[0]
: this.parent.grid.getRowByIndex(rowIndex);
this.selectedRecord = this.parent[this.selectedRecords] = selectedItemIndex !== -1 ?
tObj.getCurrentViewRecords()[parseInt(selectedItemIndex.toString(), 10)]
: this.selectedItem;
if (request === 'indent') {
var record_1 = tObj.getCurrentViewRecords()[this.selectedRow.rowIndex - 1];
var dropIndex = void 0;
if (this.selectedRow.rowIndex === 0 || this.selectedRow.rowIndex === -1 ||
tObj.getCurrentViewRecords()[this.selectedRow.rowIndex].level - record_1.level === 1) {
return;
}
if (record_1.level > this.selectedRecord.level) {
for (var i = 0; i < tObj.getCurrentViewRecords().length; i++) {
if (tObj.getCurrentViewRecords()[parseInt(i.toString(), 10)].taskData ===
record_1.parentItem.taskData) {
dropIndex = i;
if (tObj.enableVirtualization) {
dropIndex = parseInt(tObj.getRows()[parseInt(i.toString(), 10)].getAttribute('aria-rowindex'), 10) - 1;
}
}
}
}
else {
dropIndex = this.selectedRow.rowIndex - 1;
}
if (this.parent.enableVirtualization && this.selectedRecord && !(record_1.level > this.selectedRecord.level)) {
dropIndex = parseInt(this.selectedRow.getAttribute('aria-rowindex'), 10) - 2;
}
tObj["" + action] = 'indenting';
tObj["" + droppedIndex] = dropIndex;
this.eventTrigger('indenting', dropIndex);
}
else if (request === 'outdent') {
var isInvalidSelection = this.selectedRow.rowIndex === -1 || this.selectedRow.rowIndex === 0;
var isRootLevel = tObj.getCurrentViewRecords()[this.selectedRow.rowIndex].level === 0;
if (isInvalidSelection || isRootLevel) {
return;
}
var parentItem_1 = this.selectedRecord.parentItem;
var records = tObj.getCurrentViewRecords();
var dropIndex = records.findIndex(function (record) { return record.uniqueID === parentItem_1.uniqueID; });
if (dropIndex === -1) {
return;
}
if (this.parent.enableVirtualization && this.selectedRecord) {
var ariaRowIndex = this.parent.getRows()[parseInt(dropIndex.toString(), 10)].getAttribute('aria-rowindex');
dropIndex = parseInt(ariaRowIndex, 10) - 1;
}
tObj["" + action] = 'outdenting';
tObj["" + droppedIndex] = dropIndex;
this.eventTrigger('outdenting', dropIndex);
}
}
};
/**
* Triggers a specified event for the TreeGrid, notifying subscribers about the event occurrence.
*
* @param {string} action - The action to be triggered, either 'indenting' or 'outdenting'.
* @param {number} dropIndex - The index at which the row should be dropped.
* @returns {void}
*/
RowDD.prototype.eventTrigger = function (action, dropIndex) {
var _this = this;
var actionArgs = {
action: action,
cancel: false,
data: [this.parent[this.selectedRecords]],
row: this.parent[this.selectedRows]
};
this.parent.trigger(events.actionBegin, actionArgs, function (actionArgs) {
if (!actionArgs.cancel) {
if (actionArgs.action === 'indenting') {
if (_this.parent.enableVirtualization) {
_this.reorderRows([parseInt(_this.selectedRow.getAttribute('aria-rowindex'), 10) - 1], dropIndex, 'child');
}
else {
_this.reorderRows([_this.selectedRow.rowIndex], dropIndex, 'child');
}
}
else if (actionArgs.action === 'outdenting') {
if (_this.parent.enableVirtualization) {
_this.reorderRows([parseInt(_this.selectedRow.getAttribute('aria-rowindex'), 10) - 1], dropIndex, 'below');
}
else {
_this.reorderRows([_this.selectedRow.rowIndex], dropIndex, 'below');
}
}
}
});
};
/**
* Reorders the flat data array of the TreeGrid and updates the index of each record.
*
* @param {ITreeData[]} currentData - The array of tree data records to reorder.
* @returns {ITreeData[]} The updated array of tree data records with indices set.
*/
RowDD.prototype.orderToIndex = function (currentData) {
for (var i = 0; i < currentData.length; i++) {
currentData[parseInt(i.toString(), 10)].index = i;
if (!isNullOrUndefined(currentData[parseInt(i.toString(), 10)].parentItem)) {
var updatedParent = getValue('uniqueIDCollection.' + currentData[parseInt(i.toString(), 10)].parentUniqueID, this.parent);
currentData[parseInt(i.toString(), 10)].parentItem.index = updatedParent.index;
}
}
return currentData;
};
/**
* Handles the addition of new rows to the TreeGrid.
*
* @param {Object} e - The event object containing information about the rows being added.
* @param {number} e.toIndex - The index at which the new rows should be added in the TreeGrid.
* @param {Object[]} e.records - An array of the records to be added to the TreeGrid.
*
* @returns {void} This function does not return any value.
*/
RowDD.prototype.rowsAdded = function (e) {
var draggedRecord;
var dragRecords = e.records;
for (var i = e.records.length - 1; i > -1; i--) {
draggedRecord = dragRecords[parseInt(i.toString(), 10)];
if (draggedRecord.parentUniqueID) {
var record = dragRecords.filter(function (data) {
return data.uniqueID === draggedRecord.parentUniqueID;
});
if (record.length) {
var index = record[0].childRecords.indexOf(draggedRecord);
var parentRecord = record[0];
if (index !== -1) {
if (isNullOrUndefined(this.parent.idMapping)) {
parentRecord.childRecords.splice(index, 1);
if (!parentRecord.childRecords.length) {
parentRecord.hasChildRecords = false;
parentRecord.hasFilteredChildRecords = false;
}
}
this.isDraggedWithChild = true;
}
}
}
}
if (isNullOrUndefined(this.parent.dataSource) || !this.parent.dataSource.length) {
var tObj = this.parent;
var draggedRecord_1;
var dragRecords_1 = e.records;
var dragLength = e.records.length;
for (var i = dragLength - 1; i > -1; i--) {
draggedRecord_1 = dragRecords_1[parseInt(i.toString(), 10)];
if (!i && draggedRecord_1.hasChildRecords) {
draggedRecord_1.taskData[this.parent.parentIdMapping] = null;
}
var recordIndex1 = 0;
if (!isNullOrUndefined(tObj.parentIdMapping)) {
tObj.childMapping = null;
}
if (!isNullOrUndefined(draggedRecord_1.taskData) && !isNullOrUndefined(tObj.childMapping) &&
!Object.prototype.hasOwnProperty.call(draggedRecord_1.taskData, tObj.childMapping)) {
draggedRecord_1.taskData[tObj.childMapping] = [];
}
if (!isNullOrUndefined(draggedRecord_1[tObj.childMapping])) {
if (Object.prototype.hasOwnProperty.call(draggedRecord_1, tObj.childMapping) &&
(draggedRecord_1[tObj.childMapping]).length && !this.isDraggedWithChild &&
!isNullOrUndefined(tObj.parentIdMapping)) {
var childData = (draggedRecord_1[tObj.childMapping]);
for (var j = 0; j < childData.length; j++) {
if (dragRecords_1.indexOf(childData[parseInt(j.toString(), 10)]) === -1) {
dragRecords_1.splice(j, 0, childData[parseInt(j.toString(), 10)]);
childData[parseInt(j.toString(), 10)].taskData = extend({}, childData[parseInt(j.toString(), 10)]);
i += 1;
}
}
}
}
if (Object.prototype.hasOwnProperty.call(draggedRecord_1, tObj.parentIdMapping)
&& draggedRecord_1[tObj.parentIdMapping] !== null
&& !this.isDraggedWithChild) {
draggedRecord_1.taskData[tObj.parentIdMapping] = null;
delete draggedRecord_1.parentItem;
delete draggedRecord_1.parentUniqueID;
}
if (isNullOrUndefined(tObj.dataSource)) {
tObj.dataSource = [];
}
tObj.dataSource.splice(recordIndex1, 0, draggedRecord_1.taskData);
}
tObj.setProperties({ dataSource: tObj.dataSource }, false);
}
else {
for (var i = 0; i < dragRecords.length; i++) {
setValue('uniqueIDCollection.' + dragRecords[parseInt(i.toString(), 10)].uniqueID, dragRecords[parseInt(i.toString(), 10)], this.parent);
}
var args = { data: e.records, dropIndex: e.toIndex };
if (this.parent.dataSource instanceof DataManager) {
this.treeGridData = this.parent.dataSource.dataSource.json;
this.treeData = this.parent.dataSource.dataSource.json;
}
else {
this.treeGridData = this.parent.grid.dataSource;
this.treeData = this.parent.dataSource;
}
if (isNullOrUndefined(this.dropPosition)) {
this.dropPosition = 'bottomSegment';
args.dropIndex = this.parent.getCurrentViewRecords().length > 1 ? this.parent.getCurrentViewRecords().length - 1 :
args.dropIndex;
args.data = args.data.map(function (i) {
if (i.hasChildRecords && isNullOrUndefined(i.parentItem)) {
i.level = 0;
return i;
}
else {
delete i.parentItem;
delete i.parentUniqueID;
i.level = 0;
return i;
}
});
}
this.dropRows(args);
}
};
/**
* Handles the removal of specified rows from the TreeGrid.
*
* @param {Object} e - The event object containing information about the removed rows.
* @param {number[]} e.indexes - An array of indexes of the rows that were removed.
* @param {Object[]} e.records - An array of the records corresponding to the removed rows.
*
* @returns {void} This function does not return any value.
*/
RowDD.prototype.rowsRemoved = function (e) {
for (var i = 0; i < e.records.length; i++) {
this.draggedRecord = e.records[parseInt(i.toString(), 10)];
if (this.draggedRecord.hasChildRecords || this.draggedRecord.parentItem &&
this.parent.grid.dataSource.
indexOf(this.getChildrecordsByParentID(this.draggedRecord.parentUniqueID)[0]) !== -1 ||
this.draggedRecord.level === 0) {
this.deleteDragRow();
}
}
};
/**
* Refreshes the data source of the TreeGrid.
*
* @returns {void} This function does not return any value.
*/
RowDD.prototype.refreshGridDataSource = function () {
var draggedRecord = this.draggedRecord;
var droppedRecord = this.droppedRecord;
var proxy = this.parent;
var temporaryDataSource;
var indexOfDroppedRecord;
if (this.parent.dataSource instanceof DataManager && isOffline(this.parent)) {
temporaryDataSource = proxy.dataSource.dataSource.json;
}
else {
temporaryDataSource = proxy.dataSource;
}
if (temporaryDataSource && (!isNullOrUndefined(droppedRecord) && !droppedRecord.parentItem)
&& !isNullOrUndefined(droppedRecord.taskData)) {
var keys = Object.keys(temporaryDataSource);
for (var i = 0; i < keys.length; i++) {
if (temporaryDataSource[parseInt(i.toString(), 10)][this.parent.childMapping] ===
droppedRecord.taskData[this.parent.childMapping]) {
indexOfDroppedRecord = i;
}
}
if (!this.parent.idMapping) {
var positionAdjustment = this.dropPosition === 'topSegment' ? 0 : 1;
if (this.dropPosition === 'topSegment' || this.dropPosition === 'bottomSegment') {
temporaryDataSource.splice(indexOfDroppedRecord + positionAdjustment, 0, draggedRecord.taskData);
}
}
}
else if (!this.parent.parentIdMapping && (!isNullOrUndefined(droppedRecord) && droppedRecord.parentItem)) {
if (this.dropPosition === 'topSegment' || this.dropPosition === 'bottomSegment') {
var record = this.getChildrecordsByParentID(droppedRecord.parentUniqueID)[0];
var childRecords = record.childRecords;
for (var i = 0; i < childRecords.length; i++) {
droppedRecord.parentItem.taskData[this.parent.childMapping][parseInt(i.toString(), 10)]
= childRecords[parseInt(i.toString(), 10)].taskData;
}
}
}
if (this.parent.parentIdMapping) {
if (draggedRecord.parentItem) {
if (this.dropPosition === 'topSegment' || this.dropPosition === 'bottomSegment') {
draggedRecord[this.parent.parentIdMapping] = droppedRecord[this.parent.parentIdMapping];
draggedRecord.taskData[this.parent.parentIdMapping] = droppedRecord[this.parent.parentIdMapping];
}
else {
draggedRecord[this.parent.parentIdMapping] = droppedRecord[this.parent.idMapping];
draggedRecord.taskData[this.parent.parentIdMapping] = droppedRecord[this.parent.idMapping];
}
}
else {
draggedRecord.taskData[this.parent.parentIdMapping] = null;
draggedRecord[this.parent.parentIdMapping] = null;
}
}
};
/**
* Removes the border from the first row of the TreeGrid.
*
* @param {HTMLTableRowElement} element - The table row element from which to remove the border.
* @returns {void} This function does not return any value.
*/
RowDD.prototype.removeFirstrowBorder = function (element) {
var canremove = this.dropPosition === 'bottomSegment';
if (this.parent.element.getElementsByClassName('e-firstrow-border').length > 0 && element &&
(element.rowIndex !== 0 || canremove)) {
this.parent.element.getElementsByClassName('e-firstrow-border')[0].remove();
}
};
/**
* Removes the border from the last row of the TreeGrid.
*
* @param {HTMLTableRowElement} element - The row element from which to remove the last row border.
* @returns {void}
*/
RowDD.prototype.removeLastrowBorder = function (element) {
if (!element) {
return;
}
var isEmptyRow = element.classList.contains('e-emptyrow') ||
element.classList.contains('e-columnheader') ||
element.classList.contains('e-detailrow');
if (isEmptyRow) {
return;
}
var lastRow = this.parent.enableVirtualization ?
this.parent.getRows()[this.parent.getCurrentViewRecords().length - 1] :
this.parent.getRowByIndex(this.parent.getCurrentViewRecords().length - 1);
var isNotLastRow = lastRow.getAttribute('data-uid') !== element.getAttribute('data-uid');
var canRemove = isNotLastRow || this.dropPosition === 'topSegment';
var lastRowBorderElement = this.parent.element.getElementsByClassName('e-lastrow-border')[0];
if (lastRowBorderElement && canRemove) {
lastRowBorderElement.remove();
}
};
/**
* Updates the icons associated with the specified rows in the TreeGrid.
*
* @param {Element[]} row - The array of row elements to update the icons for.
* @param {number} index - The index of the row being updated.
* @param {RowDragEventArgs} args - The event arguments associated with the row drag operation.
* @returns {string} The drop position ('topSegment', 'middleSegment', 'bottomSegment', or 'Invalid').
*/
RowDD.prototype.updateIcon = function (row, index, args) {
var rowEle = args.target ? closest(args.target, 'tr') : null;
this.dropPosition = undefined;
var rowPositionHeight = 0;
this.removeFirstrowBorder(rowEle);
this.removeLastrowBorder(rowEle);
for (var i = 0; i < args.rows.length; i++) {
if (!isNullOrUndefined(rowEle) && rowEle.getAttribute('data-uid') === args.rows[parseInt(i.toString(), 10)].getAttribute('data-uid')
|| !parentsUntil(args.target, 'e-gridcontent')) {
this.dropPosition = 'Invalid';
this.addErrorElem();
if (isNullOrUndefined(this.parent.rowDropSettings.targetID)) {
this.removetopOrBottomBorder();
this.removeChildBorder();
}
}
}
// To get the corresponding drop position related to mouse position
var tObj = this.parent;
var rowTop = 0;
var roundOff = 0;
var toolHeight = tObj.toolbar && tObj.toolbar.length ?
document.getElementById(tObj.element.id + '_gridcontrol_toolbarItems').offsetHeight : 0;
// tObj.lastRow = tObj.getRowByIndex(tObj.getCurrentViewRecords().length - 1);
var positionOffSet = this.getOffset(tObj.element);
// let contentHeight1: number = (tObj.element.offsetHeight - (tObj.getContent() as HTMLElement).offsetHeight) + positionOffSet.top;
var contentHeight = tObj.getHeaderContent().offsetHeight + positionOffSet.top + toolHeight;
var scrollTop = tObj.getContent().firstElementChild.scrollTop;
if (!isNullOrUndefined(rowEle)) {
rowPositionHeight = rowEle.offsetTop - scrollTop;
}
// let scrollTop = (tObj.grid.scrollModule as any).content.scrollTop;
if (this.parent.enableVirtualization) {
rowTop = rowEle.getBoundingClientRect().top;
}
else {
rowTop = rowPositionHeight + contentHeight + roundOff;
}
var rowBottom = row[0].offsetHeight !== 0 && isNullOrUndefined(rowEle) ?
rowTop + row[0].offsetHeight : rowTop + rowEle.offsetHeight;
var difference = rowBottom - rowTop;
var divide = difference / 3;
var topRowSegment = rowTop + divide;
var middleRowSegment = topRowSegment + divide;
var bottomRowSegment = middleRowSegment + divide;
var mouseEvent = getObject('originalEvent.event', args);
var touchEvent = getObject('originalEvent.event', args);
var posy = (mouseEvent.type === 'mousemove') ? mouseEvent.pageY : ((!isNullOrUndefined(touchEvent) &&
!isNullOrUndefined(touchEvent.changedTouches)) ? touchEvent.changedTouches[0].pageY : null);
if (this.parent.enableVirtualization) {
posy = (mouseEvent.type === 'mousemove') ? mouseEvent.clientY : ((!isNullOrUndefined(touchEvent) &&
!isNullOrUndefined(touchEvent.changedTouches)) ? touchEvent.changedTouches[0].clientY : null);
}
var isTopSegment = posy <= topRowSegment;
var isMiddleRowSegment = (posy > topRowSegment && posy <= middleRowSegment);
var isBottomRowSegment = (posy > middleRowSegment && posy <= bottomRowSegment);
var isBorderNeed = true;
if (isTopSegment || isMiddleRowSegment || isBottomRowSegment) {
if (isTopSegment && this.dropPosition !== 'Invalid') {
this.removeChildBorder();
this.dropPosition = 'topSegment';
this.removetopOrBottomBorder();
this.addFirstrowBorder(rowEle);
this.removeErrorElem();
this.removeLastrowBorder(rowEle);
}
if (isMiddleRowSegment && this.dropPosition !== 'Invalid') {
this.removetopOrBottomBorder();
this.dropPosition = 'middleSegment';
this.addLastRowborder(rowEle);
this.addFirstrowBorder(rowEle);
}
if (isBottomRowSegment && this.dropPosition !== 'Invalid') {
this.removeErrorElem();
this.removetopOrBottomBorder();
this.removeChildBorder();
this.dropPosition = 'bottomSegment';
this.addLastRowborder(rowEle);
this.removeFirstrowBorder(rowEle);
}
if ((isTopSegment || isBottomRowSegment) && this.dropPosition !== 'Invalid') {
isBorderNeed = this.updateBorderStatus(row, index);
this.topOrBottomBorder(args.target, isBorderNeed);
}
else if (isMiddleRowSegment && this.dropPosition !== 'Invalid') {
var rowElement = [];
var element = closest(args.target, 'tr');
rowElement = [].slice.call(element.querySelectorAll('.e-rowcell,.e-rowdragdrop,.e-detailrowcollapse'));
isBorderNeed = this.updateBorderStatus(row, index);
if (rowElement.length > 0 && isBorderNeed) {
this.addRemoveClasses(rowElement, true, 'e-childborder');
}
}
}
return this.dropPosition;
};
/**
* Updates the border status for a specified row and index.
*
* @private
* @param {Element[]} row - The array of row elements to be updated.
* @param {number} index - The index of the row element for which the border status is to be updated.
* @returns {boolean} - Returns true if the border status was successfully updated, otherwise false.
*/
RowDD.prototype.updateBorderStatus = function (row, index) {
var _this = this;
var isBorderNeed = true;
var rows = this.parent.grid.getRows();
var childRows = [];
var hasDetailTemplate = false;
if (!isNullOrUndefined(this.parent.detailTemplate)) {
rows = this.parent.getDataRows();
hasDetailTemplate = true;
}
var treegridColumnIndex = this.parent.treeColumnIndex;
var treeColIndex = this.parent.allowRowDragAndDrop ?
(hasDetailTemplate ? treegridColumnIndex + 2 : treegridColumnIndex + 1) :
(hasDetailTemplate ? treegridColumnIndex + 1 : treegridColumnIndex);
if (!isNullOrUndefined(this.parent.rowDropSettings.targetID)) {
treeColIndex = treegridColumnIndex;
}
var dragRows = row;
var targetRow = [rows["" + index]];
if (this.dropPosition === 'topSegment') {
row.filter(function (e) {
if (isNullOrUndefined(e) || isNullOrUndefined(e.cells) || isNullOrUndefined(targetRow[0]) ||
isNullOrUndefined(targetRow[0].cells)) {
return true;
}
var regex = /index(\d+)|level(\d+)/g;
var parentIndexLevel = e === null || e === undefined ? undefined : e.cells["" + treeColIndex].className.match(regex);
var dropIndexLevel = targetRow[0].cells["" + treeColIndex].className.match(regex);
if (isNullOrUndefined(dropIndexLevel) || isNullOrUndefined(dropIndexLevel)) {
return true;
}
var parentLevel = +parentIndexLevel[1].match(/\d+/)[0];
var dropParentLevel = +dropIndexLevel[1].match(/\d+/)[0];
var InDraggedRowIndex = false;
if (parentLevel !== 0 && parentLevel !== dropParentLevel) {
return true;
}
for (var i = 0; i < rows.length; i++) {
if (rows[parseInt(i.toString(), 10)] === dragRows[0]) {
InDraggedRowIndex = true;
}
if (InDraggedRowIndex && rows[parseInt(i.toString(), 10)] !== dragRows[0]) {
var parentIndexLevelInRow = rows[parseInt(i.toString(), 10)].cells["" + treeColIndex].className.match(regex);
var parentLevelInRow = +parentIndexLevelInRow[1].match(/\d+/)[0];
if (parentLevelInRow !== parentLevel && parentLevelInRow > parentLevel) {
childRows.push(rows[parseInt(i.toString(), 10)]);
}
else {
break;
}
}
}
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))) {
isBorderNeed = false;
}
return true;
});
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;
}
if (this.dropPosition === 'bottomSegment') {
targetRow.filter(function (e) {
if (isNullOrUndefined(e) || isNullOrUndefined(e.cells) || isNullOrUndefined(dragRows[0]) ||
isNullOrUndefined(dragRows[0].cells)) {
return true;
}
var regex = /index(\d+)|level(\d+)/g;
var parentIndexLevel = e === null || e === undefined ? undefined : e.cells["" + treeColIndex].className.match(regex);
var dragIndexLevel = dragRows[0].cells["" + treeColIndex].className.match(regex);
if (isNullOrUndefined(dragIndexLevel) || isNullOrUndefined(parentIndexLevel)) {
return true;
}
var parentLevel = +parentIndexLevel[1].match(/\d+/)[0];
var dragParentLevel = +dragIndexLevel[1].match(/\d+/)[0];
var InDraggedRowIndex = false;
if (parentLevel !== 0 && parentLevel !== dragParentLevel) {
return true;
}
for (var i = 0; i < rows.length; i++) {
if (rows[parseInt(i.toString(), 10)] === targetRow[0]) {
InDraggedRowIndex = true;
}
if (InDraggedRowIndex && rows[parseInt(i.toString(), 10)] !== targetRow[0]) {
var parentIndexLevelInRow = rows[parseInt(i.toString(), 10)].cells["" + treeColIndex].className.match(regex);
var parentLevelInRow = +parentIndexLevelInRow[1].match(/\d+/)[0];
if (parentLevelInRow !== parentLevel && parentLevelInRow > parentLevel) {
childRows.push(rows[parseInt(i.toString(), 10)]);
}
else {
break;
}
}
}
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))) {
isBorderNeed = false;
}
return true;
});
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;
}
if (this.dropPosition === 'middleSegment') {
targetRow.filter(function (e) {
if (isNullOrUndefined(e) || isNullOrUndefined(e.cells) || isNullOrUndefined(dragRows[0]) ||
isNullOrUndefined(dragRows[0].cells)) {
return true;
}
for (var i = 0; i < dragRows.length; i++) {
var regex = /index(\d+)|level(\d+)/g;
var dropActualIndex = targetRow[0].rowIndex;
var dragIndexLevel = dragRows[parseInt(i.toString(), 10)].cells["" + treeColIndex].className.match(regex);
if (!dragIndexLevel) {
return true;
}
var dragIndex = parseInt(dragIndexLevel.find(function (item) { return item.includes('index'); }).match(/\d+/)[0] || '0', 10);
if (hasDetailTemplate) {
dropActualIndex = dropActualIndex / 2;
}
if (dragIndex === dropActualIndex && !_this.parent.rowDropSettings.targetID) {
isBorderNeed = false;
}
else {
isBorderNeed = true;
break;
}
}
if (!isBorderNeed) {
_this.dropPosition = 'Invalid';
_this.addErrorElem();
}
return isBorderNeed;
});
}
this.canDrop = isBorderNeed;
return isBorderNeed;
};
/**
* Removes the visual border from all child rows within the TreeGrid.
*
* @returns {void} No return value.
*/
RowDD.prototype.removeChildBorder = function () {
var borderElem = [];
borderElem = [].slice.call(this.parent.element.querySelectorAll('.e-childborder'));
if (borderElem.length > 0) {
this.addRemoveClasses(borderElem, false, 'e-childborder');
}
};
/**
* Adds a visual border to the first row of the TreeGrid.
*
* @param {HTMLTableRowElement} targetRow - The target row element to which the border will be added, if it is the first row.
* @returns {void} No return value.
*/
RowDD.prototype.addFirstrowBorder = function (targetRow) {
var node = this.parent.element;
var tObj = this.parent;
if (targetRow && targetRow.rowIndex === 0 && !targetRow.classList.contains('e-emptyrow')) {
var div = this.parent.createElement('div', { className: 'e-firstrow-border' });
var gridheaderEle = this.parent.getHeaderContent();
var toolbarHeight = 0;
if (tObj.toolbar) {
toolbarHeight = tObj.toolbarModule.getToolbar().offsetHeight;
}
var multiplegrid = !isNullOrUndefined(this.parent.rowDropSettings.targetID);
if (multiplegrid) {
div.style.top = this.parent.grid.element.getElementsByClassName('e-gridheader')[0].offsetHeight
+ toolbarHeight + 'px';
}
div.style.width = multiplegrid ? node.offsetWidth + 'px' :
node.offsetWidth - this.getScrollWidth() + 'px';
if (!gridheaderEle.querySelectorAll('.e-firstrow-border').length) {
gridheaderEle.appendChild(div);
}
}
};
/**
* Adds a visual border to the last row of the TreeGrid.
*
* @param {HTMLTableRowElement} trElement - The table row element to which the border will be added, if it is the last row.
* @returns {void} No return value.
*/
RowDD.prototype.addLastRowborder = function (trElement) {
if (!trElement) {
return;
}
var isEmptyRow = trElement && (trElement.classList.contains('e-emptyrow') ||
trElement.classList.contains('e-columnheader') || trElement.classList.contains('e-detailrow'));
if (isEmptyRow) {
return;
}
if (trElement && !isEmptyRow && this.parent.getRows()[this.parent.getCurrentViewRecords().length - 1].getAttribute('data-uid') ===
trElement.getAttribute('data-uid')) {
var bottomborder = this.parent.createElement('div', { className: 'e-lastrow-border' });
var gridcontentEle = this.parent.getContent();
bottomborder.style.width = this.parent.element.offsetWidth - this.getScrollWidth() + 'px';
if (!gridcontentEle.querySelectorAll('.e-lastrow-border').length) {
gridcontentEle.classList.add('e-treegrid-relative');
gridcontentEle.appendChild(bottomborder);
bottomborder.style.bottom = this.getScrollWidth() + 'px';
}
}
};
/**
* Retrieves the total scroll width of the TreeGrid content area.
*
* @returns {number} The width of the scrollbar if content overflows, otherwise 0.
*/
RowDD.prototype.getScrollWidth = function () {
var scrollElem = this.parent.getContent().firstElementChild;
return scrollElem.scrollWidth > scrollElem.offsetWidth ? Scroll.getScrollBarWidth() : 0;
};
/**
* Adds an error element to the dragged row element during a row drag-and-drop operation.
*
* @returns {void} No return value.
*/
RowDD.prototype.addErrorElem = function () {
var dragelem = document.getElementsByClassName('e-cloneproperties')[0];
var errorelemCount = dragelem.querySelectorAll('.e-errorelem').length;
var sanitize = 'sanitize';
if (!errorelemCount && !this.parent.rowDropSettings.targetID) {
var errorContainer = document.createElement('div');
errorContainer.classList.add('e-errorcontainer', 'e-icons', 'e-errorelem');
var rowCell = dragelem.querySelector('.e-rowcell');
var errorVal = dragelem.querySelector('.errorValue');
var content = rowCell.innerHTML;
if (errorVal) {
content = this.parent["" + sanitize](errorVal.innerHTML);
errorVal.parentNode.removeChild(errorVal);
}
rowCell.innerHTML = '';
var spanContent = document.createElement('span');
spanContent.className = 'errorValue';
spanContent.style.paddingLeft = '16px';
spanContent.innerHTML = this.parent["" + sanitize](content);
rowCell.appendChild(errorContainer);
rowCell.appendChild(spanContent);
var dropItemSpan = document.querySelector('.e-dropitemscount');
if (this.hasDropItem && dropItemSpan) {
var dropItemLeft = parseInt(dropItemSpan.style.left, 10) + errorContainer.offsetWidth + 16;
var spanLeft = !this.parent.enableRtl ? dropItemLeft : 0;
dropItemSpan.style.left = spanLeft + "px";
this.hasDropItem = false;
}
}
};
/**
* Removes the error element from the DOM and adjusts the position of the drop item count if necessary.
*
* @returns {void} No return value.
*/
RowDD.prototype.removeErrorElem = function () {
var errorelem = document.querySelector('.e-errorelem');
var errorValue = document.querySelector('.errorValue');
var dropItemSpan = document.querySelector('.e-dropitemscount');
if (errorelem) {
if (dropItemSpan) {
var dropItemLeft = parseInt(dropItemSpan.style.left, 10) - errorelem.offsetWidth - 16;
setStyleAttribute(errorValue, {
paddingLeft: '0px'
});
if (!this.parent.enableRtl) {
setStyleAttribute(dropItemSpan, {
left: dropItemLeft + "px"
});
}
}
errorelem.remove();
}
this.hasDropItem = true;
};
/**
* Applies drop border styles to row elements based on the current drop position ('topSegment' or 'bottomSegment').
*
* @param {Element} target - The target element where the drop action is taking place.
* @param {boolean} [isBorderNeed=true] - Indicates whether a border is needed during the drop action. Defaults to `true`.
* @returns {void} No return value.
*/
RowDD.prototype.topOrBottomBorder = function (target, isBorderNeed) {
if (isBorderNeed === void 0) { isBorderNeed = true; }
var element = closest(target, 'tr');
var rowElements = element ?
Array.from(element.querySelectorAll('.e-rowcell, .e-rowdragdrop, .e-detailrowcollapse')) : [];
if (!rowElements.length) {
return;
}
var classAction = isBorderNeed ? this.addRemoveClasses.bind(this, rowElements, true) : this.addRemoveClasses.bind(this, rowElements, false, 'e-dragborder');
if (this.dropPosition === 'topSegment') {
classAction('e-droptop');
var lastRowDragBorder = this.parent.element.querySelector('.e-lastrow-dragborder');
if (lastRowDragBorder) {
lastRowDragBorder.remove();
}
}
if (this.dropPosition === 'bottomSegment') {
classAction('e-dropbottom');
}
};
/**
* Removes the drop border classes ('e-dropbottom' and 'e-droptop') from the parent element if present.
*
* @returns {void} No return value.
*/
RowDD.prototype.removetopOrBottomBorder = function () {
var border = [];
border = [].slice.call(this.parent.element.querySelectorAll('.e-dropbottom, .e-droptop'));
if (border.length) {
this.addRemoveClasses(border, false, 'e-dropbottom');
this.addRemoveClasses(border, false, 'e-droptop');
}
};
/**
* Adds or removes a specified class from a list of HTML elements.
*
* @param {Element[]} cells - The list of HTML elements to which the class will be added or removed.
* @param {boolean} add - A flag indicating whether to add (`true`) or remove (`false`) the class.
* @param {string} className - The class name to be added or removed from each element in `cells`.
* @returns {void} No return value.
*/
RowDD.prototype.addRemoveClasses = function (cells, add, className) {
for (var i = 0, len = cells.length; i < len; i++) {
if (add) {
cells[parseInt(i.toString(), 10)].classList.add(className);
}
else {
cells[parseInt(i.toString(), 10)].classList.remove(className);
}
}
};
/**
* Calculates the offset position of the specified HTML element relative to the document.
*
* @param {Element} element - The HTML element for which the offset position is calculated.
* @returns {PositionOffSet} The offset position containing `top` and `left` values.
*/
RowDD.prototype.getOffset = function (element) {
var box = element.getBoundingClientR