@syncfusion/ej2-grids
Version:
Feature-rich JavaScript datagrid (datatable) control with built-in support for editing, filtering, grouping, paging, sorting, and exporting to Excel.
524 lines (523 loc) • 26.6 kB
JavaScript
import { removeClass, addClass, extend, EventHandler } from '@syncfusion/ej2-base';
import { closest, classList, isNullOrUndefined } from '@syncfusion/ej2-base';
import { Grid } from '../base/grid';
import { parents, getUid, appendChildren, isComplexField, getObject } from '../base/util';
import * as events from '../base/constant';
import { AriaService } from '../services/aria-service';
import { Row } from '../models/row';
import { Cell } from '../models/cell';
import { CellType } from '../base/enum';
import * as literals from '../base/string-literals';
/**
* The `DetailRow` module is used to handle detail template and hierarchy Grid operations.
*/
var DetailRow = /** @class */ (function () {
/**
* Constructor for the Grid detail template module
*
* @param {IGrid} parent - specifies the IGrid
* @param {ServiceLocator} locator - specifes the serviceLocator
* @hidden
*/
function DetailRow(parent, locator) {
//Internal variables
this.aria = new AriaService();
this.childRefs = [];
this.parent = parent;
this.serviceLocator = locator;
this.focus = locator.getService('focus');
this.addEventListener();
}
/**
* @returns {void}
* @hidden
*/
DetailRow.prototype.addEventListener = function () {
if (this.parent.isDestroyed) {
return;
}
EventHandler.add(this.parent.element, 'auxclick', this.auxilaryclickHandler, this);
this.parent.on(events.click, this.clickHandler, this);
this.parent.on(events.destroy, this.destroy, this);
this.parent.on(events.keyPressed, this.keyPressHandler, this);
this.parent.on(events.expandChildGrid, this.expand, this);
this.parent.on(events.columnVisibilityChanged, this.refreshColSpan, this);
this.parent.on(events.destroy, this.destroyChildGrids, this);
this.parent.on(events.destroyChildGrid, this.destroyChildGrids, this);
this.parent.on(events.destroy, this.detachDetailTemplate, this);
this.parent.on(events.detachDetailTemplate, this.detachDetailTemplate, this);
};
DetailRow.prototype.clickHandler = function (e) {
if ((e.target.classList.contains('e-icon-grightarrow') || e.target.classList.contains('e-icon-gdownarrow'))
&& !this.parent.allowGrouping) {
e.preventDefault();
}
this.toogleExpandcollapse(closest(e.target, 'td'));
};
DetailRow.prototype.auxilaryclickHandler = function (e) {
if ((e.target.classList.contains('e-icon-grightarrow') || e.target.classList.contains('e-icon-gdownarrow'))
&& !this.parent.allowGrouping && (e.button === 1)) {
e.preventDefault();
}
};
DetailRow.prototype.toogleExpandcollapse = function (target) {
this.l10n = this.serviceLocator.getService('localization');
var gObj = this.parent;
var table = this.parent.getContentTable();
var lastrowIdx = this.parent.getCurrentViewRecords().length - 1;
var parent = 'parentDetails';
var childGrid;
var isExpanded = target && target.classList.contains('e-detailrowcollapse');
if (!(target && (target.classList.contains('e-detailrowcollapse') || target.classList.contains('e-detailrowexpand')))
|| (target && target.classList.contains('e-masked-cell'))) {
return;
}
var tr = target.parentElement;
var uid = tr.getAttribute('data-uid');
var rowObj = gObj.getRowObjectFromUID(uid);
var needToRefresh = false;
var nextRow = this.parent.getContentTable().querySelector(literals.tbody).children[tr.rowIndex + 1];
if (target.classList.contains('e-detailrowcollapse')) {
var data_1 = rowObj.data;
if (this.isDetailRow(nextRow)) {
nextRow.style.display = '';
gObj.notify(events.detailStateChange, { data: data_1,
childGrid: gObj.childGrid, detailElement: target, isExpanded: isExpanded });
needToRefresh = true;
}
else if (gObj.getDetailTemplate() || gObj.childGrid) {
var rowId = getUid('grid-row');
var detailRow = this.parent.createElement('tr', { className: 'e-detailrow', attrs: { 'data-uid': rowId, role: 'row' } });
var detailCell_1 = this.parent.createElement('th', { className: 'e-detailcell', attrs: { 'scope': 'col', role: 'columnheader' } });
var colSpan = this.parent.getVisibleColumns().length;
if (this.parent.allowRowDragAndDrop) {
colSpan++;
}
detailCell_1.setAttribute('colspan', colSpan.toString());
var row = new Row({
isDataRow: true,
isExpand: true,
uid: rowId,
isDetailRow: true,
cells: [new Cell({ cellType: CellType.Indent }), new Cell({ isDataCell: true, visible: true })]
});
row.parentUid = rowObj.uid;
for (var i = 0, len = gObj.groupSettings.columns.length; i < len; i++) {
detailRow.appendChild(this.parent.createElement('td', { className: 'e-indentcell' }));
row.cells.unshift(new Cell({ cellType: CellType.Indent }));
}
detailRow.appendChild(this.parent.createElement('th', { className: 'e-detailindentcell', attrs: { 'scope': 'col' } }));
detailRow.appendChild(detailCell_1);
tr.parentNode.insertBefore(detailRow, tr.nextSibling);
var isReactCompiler = void 0;
var isReactChild = void 0;
if (gObj.detailTemplate) {
isReactCompiler = this.parent.isReact && typeof (gObj.detailTemplate) !== 'string' &&
!(gObj.detailTemplate.prototype && gObj.detailTemplate.prototype.CSPTemplate);
isReactChild = this.parent.parentDetails && this.parent.parentDetails.parentInstObj &&
this.parent.parentDetails.parentInstObj.isReact;
var isReactPrintGrid = this.parent.printGridParent && this.parent.printGridParent.isReact;
var detailTemplateID = gObj.element.id + 'detailTemplate';
if (isReactCompiler || isReactChild || isReactPrintGrid) {
gObj.getDetailTemplate()(data_1, gObj, 'detailTemplate', detailTemplateID, null, null, detailCell_1);
this.parent.renderTemplates(function () {
gObj.trigger(events.detailDataBound, { detailElement: detailCell_1, data: data_1, childGrid: childGrid });
});
}
else {
appendChildren(detailCell_1, gObj.getDetailTemplate()(data_1, gObj, 'detailTemplate', detailTemplateID, undefined, undefined, undefined, this.parent['root']));
}
}
else {
childGrid = new Grid(this.getGridModel(gObj, rowObj, gObj.printMode));
childGrid.height = gObj.enableInfiniteScrolling && childGrid.height === 'auto' ? 300 : childGrid.height;
childGrid.root = gObj.root ? gObj.root : gObj;
this.childRefs.push(childGrid);
if (childGrid.query) {
childGrid.query = childGrid.query.clone();
}
childGrid["" + parent] = {
parentID: gObj.element.id,
parentPrimaryKeys: gObj.getPrimaryKeyFieldNames(),
parentKeyField: gObj.childGrid.queryString,
parentKeyFieldValue: gObj.childGrid.queryString && isComplexField(gObj.childGrid.queryString) ?
getObject(gObj.childGrid.queryString, data_1) : data_1[gObj.childGrid.queryString],
parentRowData: data_1
};
if (gObj.isReact || gObj.isVue) {
childGrid.parentDetails.parentInstObj = gObj;
}
else if (gObj.parentDetails && gObj.parentDetails.parentInstObj && (gObj.parentDetails.parentInstObj.isReact
|| gObj.parentDetails.parentInstObj.isVue)) {
childGrid.parentDetails.parentInstObj = gObj.parentDetails.parentInstObj;
}
if (gObj.printGridParent && gObj.printGridParent.isReact) {
childGrid.printGridParent = gObj.printGridParent;
}
childGrid.isLegacyTemplate = gObj.isReact
|| gObj.isLegacyTemplate;
if (gObj.isPrinting) {
childGrid.isPrinting = true;
childGrid.on(events.contentReady, this.promiseResolve(childGrid), this);
childGrid.on(events.onEmpty, this.promiseResolve(childGrid), this);
}
rowObj.childGrid = childGrid;
var modules = childGrid.getInjectedModules();
var injectedModues = gObj.getInjectedModules();
if (!modules || modules.length !== injectedModues.length) {
childGrid.setInjectedModules(injectedModues);
}
var gridElem = this.parent.createElement('div', {
id: 'child' + parents(tr, 'e-grid').length +
'_grid' + tr.rowIndex + getUid(''), className: 'e-childgrid'
});
detailCell_1.appendChild(gridElem);
childGrid.appendTo(gridElem);
}
detailRow.appendChild(detailCell_1);
if (tr.nextSibling) {
tr.parentNode.insertBefore(detailRow, tr.nextSibling);
}
else {
tr.parentNode.appendChild(detailRow);
}
var rowElems = gObj.getRows();
var rowObjs = gObj.getRowsObject();
rowElems.splice(rowElems.indexOf(tr) + 1, 0, detailRow);
if (gObj.enableInfiniteScrolling && gObj.infiniteScrollSettings.enableCache) {
var infiniteCache = gObj.contentModule
.infiniteCache;
var keys = Object.keys(infiniteCache);
for (var i = 0; i < keys.length; i++) {
var cacheIndex = infiniteCache[parseInt(keys[parseInt(i.toString(), 10)], 10)].indexOf(rowObj);
if (cacheIndex !== -1) {
infiniteCache[parseInt(keys[parseInt(i.toString(), 10)], 10)].splice(cacheIndex + 1, 0, row);
break;
}
}
}
else {
rowObjs.splice(rowObjs.indexOf(rowObj) + 1, 0, row);
}
if (!isReactCompiler || !isReactChild) {
gObj.trigger(events.detailDataBound, { detailElement: detailCell_1, data: data_1, childGrid: childGrid });
}
gObj.notify(events.detailDataBound, { rows: rowObjs });
}
classList(target, ['e-detailrowexpand'], ['e-detailrowcollapse']);
classList(target.firstElementChild, ['e-dtdiagonaldown', 'e-icon-gdownarrow'], ['e-dtdiagonalright', 'e-icon-grightarrow']);
rowObj.isExpand = true;
if (target.classList.contains('e-lastrowcell') && this.parent.getContent().clientHeight > table.scrollHeight) {
removeClass(target.parentElement.querySelectorAll('td'), 'e-lastrowcell');
var detailrowIdx = table.querySelector(literals.tbody).getElementsByClassName('e-detailrow').length - 1;
addClass(table.querySelector(literals.tbody).getElementsByClassName('e-detailrow')[parseInt(detailrowIdx.toString(), 10)].childNodes, ['e-lastrowcell']);
this.lastrowcell = true;
}
this.aria.setExpand(target, true);
target.firstElementChild.setAttribute('title', this.l10n.getConstant('Expanded'));
}
else {
if (this.isDetailRow(nextRow)) {
nextRow.style.display = 'none';
gObj.notify(events.detailStateChange, { data: rowObj.data,
childGrid: gObj.childGrid, detailElement: target, isExpanded: isExpanded });
}
classList(target, ['e-detailrowcollapse'], ['e-detailrowexpand']);
classList(target.firstElementChild, ['e-dtdiagonalright', 'e-icon-grightarrow'], ['e-dtdiagonaldown', 'e-icon-gdownarrow']);
if (parseInt(tr.getAttribute(literals.ariaRowIndex), 10) - 1 === lastrowIdx && this.lastrowcell) {
addClass(target.parentElement.querySelectorAll('td'), 'e-lastrowcell');
this.lastrowcell = false;
}
rowObj.isExpand = false;
needToRefresh = true;
this.aria.setExpand(target, false);
target.firstElementChild.setAttribute('title', this.l10n.getConstant('Collapsed'));
}
if (!isNullOrUndefined(gObj.detailTemplate) || (gObj.childGrid && needToRefresh)) {
gObj.updateVisibleExpandCollapseRows();
gObj.notify(events.refreshExpandandCollapse, { rows: gObj.getRowsObject() });
}
if (this.parent.allowTextWrap && this.parent.height === 'auto') {
if (this.parent.getContentTable().scrollHeight > this.parent.getContent().clientHeight) {
this.parent.scrollModule.setPadding();
}
else {
this.parent.scrollModule.removePadding();
}
}
};
/**
* @hidden
* @param {IGrid} gObj - specifies the grid Object
* @param {Row<Column>}rowObj - specifies the row object
* @param {string} printMode - specifies the printmode
* @returns {Object} returns the object
*/
DetailRow.prototype.getGridModel = function (gObj, rowObj, printMode) {
var gridModel;
if (gObj.isPrinting && rowObj.isExpand && gObj.expandedRows &&
gObj.expandedRows[rowObj.index] && gObj.expandedRows[rowObj.index].gridModel) {
gObj.expandedRows[rowObj.index].gridModel.hierarchyPrintMode = gObj.childGrid.hierarchyPrintMode;
gridModel = extend({}, gObj.expandedRows[rowObj.index].gridModel, gObj.childGrid, true);
}
else {
if (gObj.isPrinting && gObj.childGrid.allowPaging) {
gObj.childGrid.allowPaging = printMode === 'CurrentPage';
}
gridModel = extend({}, {}, gObj.childGrid, true);
}
return gridModel;
};
DetailRow.prototype.promiseResolve = function (grid) {
var _this = this;
return function () {
grid.off(events.contentReady, _this.promiseResolve);
grid.off(events.onEmpty, _this.promiseResolve);
grid.notify(events.hierarchyPrint, {});
};
};
DetailRow.prototype.isDetailRow = function (row) {
return row && row.classList.contains('e-detailrow');
};
DetailRow.prototype.destroy = function () {
var gridElement = this.parent.element;
if (this.parent.isDestroyed || !gridElement || (!gridElement.querySelector('.' + literals.gridHeader) &&
!gridElement.querySelector('.' + literals.gridContent))) {
return;
}
EventHandler.remove(this.parent.element, 'auxclick', this.auxilaryclickHandler);
this.parent.off(events.click, this.clickHandler);
this.parent.off(events.destroy, this.destroy);
this.parent.off(events.keyPressed, this.keyPressHandler);
this.parent.off(events.expandChildGrid, this.expand);
this.parent.off(events.columnVisibilityChanged, this.refreshColSpan);
this.parent.off(events.destroy, this.destroyChildGrids);
this.parent.off(events.destroyChildGrid, this.destroyChildGrids);
this.parent.off(events.destroy, this.detachDetailTemplate);
this.parent.off(events.detachDetailTemplate, this.detachDetailTemplate);
};
DetailRow.prototype.getTDfromIndex = function (index, className) {
var tr = !isNullOrUndefined(index) ? this.parent.getDataRows()[parseInt(index.toString(), 10)] : undefined;
if (tr && tr.querySelector(className)) {
return tr.querySelector(className);
}
return null;
};
/**
* Expands a detail row with the given target.
*
* @param {Element} target - Defines the collapsed element to expand.
* @returns {void}
*/
DetailRow.prototype.expand = function (target) {
if (!isNaN(target)) {
target = this.getTDfromIndex(target, '.e-detailrowcollapse');
}
if (target && target.classList.contains('e-detailrowcollapse')) {
this.toogleExpandcollapse(target);
}
};
/**
* Collapses a detail row with the given target.
*
* @param {Element} target - Defines the expanded element to collapse.
* @returns {void}
*/
DetailRow.prototype.collapse = function (target) {
if (!isNaN(target)) {
target = this.getTDfromIndex(target, '.e-detailrowexpand');
}
if (target && target.classList.contains('e-detailrowexpand')) {
this.toogleExpandcollapse(target);
}
};
/**
* Expands all the detail rows of the Grid.
*
* @returns {void}
*/
DetailRow.prototype.expandAll = function () {
this.expandCollapse(true);
this.parent.trigger(events.actionComplete, { requestType: 'expandAllComplete', type: events.actionComplete, moduleObj: this });
};
/**
* Collapses all the detail rows of the Grid.
*
* @returns {void}
*/
DetailRow.prototype.collapseAll = function () {
this.expandCollapse(false);
this.parent.trigger(events.actionComplete, { requestType: 'collapseAllComplete', type: events.actionComplete, moduleObj: this });
};
DetailRow.prototype.expandCollapse = function (isExpand) {
var td;
var rows = this.parent.getDataRows();
for (var i = 0, len = rows.length; i < len; i++) {
td = rows[parseInt(i.toString(), 10)].querySelector('.e-detailrowcollapse, .e-detailrowexpand');
if (isExpand) {
this.expand(td);
}
else {
this.collapse(td);
}
}
};
DetailRow.prototype.keyPressHandler = function (e) {
var gObj = this.parent;
var isMacLike = /(Mac)/i.test(navigator.platform);
if (isMacLike && e.metaKey) {
if (e.action === 'downArrow') {
e.action = 'ctrlDownArrow';
}
else if (e.action === 'upArrow') {
e.action = 'ctrlUpArrow';
}
}
switch (e.action) {
case 'ctrlDownArrow':
this.expandAll();
break;
case 'ctrlUpArrow':
this.collapseAll();
break;
case 'altUpArrow':
case 'altDownArrow':
// eslint-disable-next-line no-case-declarations
var selected = gObj.allowSelection ? gObj.getSelectedRowIndexes() : [];
if (selected.length) {
var dataRow = gObj.getDataRows()[selected[selected.length - 1]];
var td = dataRow.querySelector('.e-detailrowcollapse, .e-detailrowexpand');
if (e.action === 'altDownArrow') {
this.expand(td);
}
else {
this.collapse(td);
}
}
break;
case 'enter':
if (this.parent.isEdit) {
return;
}
// eslint-disable-next-line no-case-declarations
var element = this.focus.getFocusedElement();
if (element && (element.classList.contains('e-icon-grightarrow') || element.classList.contains('e-icon-gdownarrow'))) {
element = element.parentElement;
}
if (element && !element.classList.contains('e-detailrowcollapse') &&
!element.classList.contains('e-detailrowexpand')) {
break;
}
this.toogleExpandcollapse(element);
break;
}
};
DetailRow.prototype.refreshColSpan = function () {
var detailrows = this.parent.contentModule.getTable().querySelectorAll('tr.e-detailrow');
var colSpan = this.parent.getVisibleColumns().length;
for (var i = 0; i < detailrows.length; i++) {
detailrows[parseInt(i.toString(), 10)].querySelector('.e-detailcell').setAttribute('colspan', colSpan + '');
}
};
DetailRow.prototype.destroyChildGrids = function (args) {
var gObj = this.parent;
if (gObj.enableInfiniteScrolling && (gObj.childGrid || gObj.detailTemplate) && args.requestType === 'infiniteScroll'
&& gObj.infiniteScrollSettings.enableCache) {
var cacheIndex = args.direction === 'down'
? args.currentPage - gObj.infiniteScrollSettings.initialBlocks
: args.currentPage + gObj.infiniteScrollSettings.initialBlocks;
var infiniteCache_1 = gObj.contentModule
.infiniteCache[parseInt(cacheIndex.toString(), 10)];
var detailRows_1 = infiniteCache_1.filter(function (data) { return data.isDetailRow && data.parentUid; });
if (gObj.childGrid) {
var _loop_1 = function (i) {
var detailRow = gObj.getContentTable()
.querySelector('[data-uid="' + detailRows_1[parseInt(i.toString(), 10)].uid + '"]');
var childGridElement = detailRow.querySelector('.e-childgrid');
var childGridIndex = this_1.childRefs.findIndex(function (grid) { return grid.element.id === childGridElement.id; });
if (!this_1.childRefs[parseInt(childGridIndex.toString(), 10)].isDestroyed) {
this_1.childRefs[parseInt(childGridIndex.toString(), 10)].destroy();
this_1.childRefs.splice(childGridIndex, 1);
}
var detailRowIndex = infiniteCache_1.indexOf(detailRows_1[parseInt(i.toString(), 10)]);
infiniteCache_1.splice(detailRowIndex, 1);
infiniteCache_1[detailRowIndex - 1].childGrid = null;
infiniteCache_1[detailRowIndex - 1].isExpand = false;
detailRow.remove();
};
var this_1 = this;
for (var i = 0; i < detailRows_1.length; i++) {
_loop_1(i);
}
}
if (gObj.detailTemplate && detailRows_1.length) {
var args_1 = [];
var _loop_2 = function (i) {
args_1.push({
detailRow: gObj.getContentTable().querySelector('[data-uid="' + detailRows_1[parseInt(i.toString(), 10)].uid + '"]'),
detailRowObject: detailRows_1[parseInt(i.toString(), 10)],
parentRowObject: infiniteCache_1.find(function (parent) { return detailRows_1[parseInt(i.toString(), 10)]
.parentUid === parent.uid; })
});
};
for (var i = 0; i < detailRows_1.length; i++) {
_loop_2(i);
}
this.parent.trigger(events.beforeDetailTemplateDetach, args_1, function () {
for (var i = 0; i < detailRows_1.length; i++) {
var detailRow = gObj.getContentTable()
.querySelector('[data-uid="' + detailRows_1[parseInt(i.toString(), 10)].uid + '"]');
var detailRowIndex = infiniteCache_1.indexOf(detailRows_1[parseInt(i.toString(), 10)]);
infiniteCache_1.splice(detailRowIndex, 1);
infiniteCache_1[detailRowIndex - 1].isExpand = false;
detailRow.remove();
}
});
}
return;
}
var rows = this.parent.getRowsObject();
for (var i = 0; i < rows.length; i++) {
rows[parseInt(i.toString(), 10)].childGrid = null;
}
for (var i = 0; i < this.childRefs.length; i++) {
if (!this.childRefs[parseInt(i.toString(), 10)].isDestroyed) {
this.childRefs[parseInt(i.toString(), 10)].destroy();
}
}
this.childRefs = [];
};
DetailRow.prototype.detachDetailTemplate = function () {
var gObj = this.parent;
if (gObj.detailTemplate) {
var rowsObject_1 = gObj.getRowsObject();
var detailRows_2 = rowsObject_1.filter(function (data) { return data.isDetailRow && data.parentUid; });
if (detailRows_2.length) {
var args_2 = [];
detailRows_2.map(function (data) {
args_2.push({
detailRow: gObj.getContentTable().querySelector('[data-uid="' + data.uid + '"]'),
detailRowObject: data,
parentRowObject: rowsObject_1.find(function (parent) { return data.parentUid === parent.uid; })
});
});
gObj.trigger(events.beforeDetailTemplateDetach, args_2, function () {
detailRows_2.map(function (data) {
gObj.getContentTable().querySelector('[data-uid="' + data.uid + '"]').remove();
});
});
}
}
};
/**
* For internal use only - Get the module name.
*
* @returns {string} returns the module name
* @private
*/
DetailRow.prototype.getModuleName = function () {
return 'detailRow';
};
return DetailRow;
}());
export { DetailRow };