UNPKG

@syncfusion/ej2-treegrid

Version:
1,176 lines (1,166 loc) 725 kB
import { merge, Property, ChildProperty, Collection, isNullOrUndefined, Browser, removeClass, addClass, getValue, createElement, setValue, extend as extend$1, Internationalization, getEnumValue, compile, Component, L10n, EventHandler, KeyboardEvents, SanitizeHtmlHelper, Complex, Event, NotifyPropertyChanges, closest, setStyleAttribute, select, classList, debounce, remove } from '@syncfusion/ej2-base'; import { Logger as Logger$1, Grid, detailLists, Clipboard, getObject, parentsUntil, Print as Print$1, templateCompiler, appendChildren, extend, CellRenderer, getUid, CellType, Freeze as Freeze$1, getNumberFormat, getActualProperties, iterateArrayOrObject, RowDropSettings as RowDropSettings$1, Reorder as Reorder$1, Resize as Resize$1, RowDD as RowDD$1, Scroll, VirtualRowModelGenerator, Filter as Filter$1, ExcelExport as ExcelExport$1, Data, ExportHelper, PdfExport as PdfExport$1, Page as Page$1, Toolbar as Toolbar$1, Aggregate as Aggregate$1, calculateAggregate, Sort as Sort$1, ColumnMenu as ColumnMenu$1, ContextMenu as ContextMenu$1, Edit as Edit$1, resetRowIndex, CommandColumn as CommandColumn$1, DetailRow as DetailRow$1, VirtualContentRenderer, Cell, getVisiblePage, InterSectionObserver, getTransformValues, VirtualScroll as VirtualScroll$1, RenderType, VirtualHeaderRenderer, ColumnChooser as ColumnChooser$1, InfiniteScroll as InfiniteScroll$1, RowRenderer } from '@syncfusion/ej2-grids'; import { createCheckBox } from '@syncfusion/ej2-buttons'; import { DataManager, ODataAdaptor, WebApiAdaptor, WebMethodAdaptor, CacheAdaptor, UrlAdaptor, Query, DataUtil, RemoteSaveAdaptor, Deferred, JsonAdaptor, Predicate as Predicate$1 } from '@syncfusion/ej2-data'; import { showSpinner, hideSpinner, createSpinner } from '@syncfusion/ej2-popups'; var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; /** * Represents the "Column" model class for TreeGrid, defining essential properties and functionalities of a column. */ class Column { constructor(options) { /** * Allows or disallows editing of the column. Set to `false` to make a column non-editable. * By default, all columns are editable. * * @default true */ this.allowEditing = true; /** * Customization options for the edit cell. * * @default {} */ this.edit = {}; /** * When set to `true`, encodes HTML content in headers and cells to prevent HTML injection. * * @default true */ this.disableHtmlEncode = true; /** * Disables column reordering if set to `false`. By default, columns can be reordered. * * @default true */ this.allowReordering = true; /** * Disables column menu for the column if set to `false`. By default, column menus are enabled for all columns. * * @default true */ this.showColumnMenu = true; /** * Disables filtering for the column if set to `false`. By default, columns are filterable. * * @default true */ this.allowFiltering = true; /** * Disables sorting for the column if set to `false`. By default, columns are sortable. * * @default true */ this.allowSorting = true; /** * Disables resizing for the column if set to `false`. By default, columns can be resized. * * @default true */ this.allowResizing = true; /** * Customize default filter options for a specific column, providing types and UI definitions for custom components. * * @default null */ this.filter = {}; merge(this, options); } /** * Reflects state changes for TreeGrid column directives, particularly in React. * * @param {Column} column - The column to update. * @returns {void} * @hidden */ setProperties(column) { const keys = Object.keys(column); for (let i = 0; i < keys.length; i++) { this[keys[parseInt(i.toString(), 10)]] = column[keys[parseInt(i.toString(), 10)]]; if (this.parent && this.parent['isReact'] && keys[parseInt(i.toString(), 10)] === 'template') { const refreshReactColumnTemplateByUid = 'refreshReactColumnTemplateByUid'; this.parent.clipboardModule['treeGridParent'].renderModule[`${refreshReactColumnTemplateByUid}`](this.uid); } } } } /** * Defines TreeGrid column */ class TreeGridColumn extends Column { } __decorate([ Property(null) ], TreeGridColumn.prototype, "columns", void 0); /** * Defines stacked tree grid column */ class StackedColumn extends TreeGridColumn { } var __decorate$1 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; /** * Configures the loading indicator for the Tree Grid, allowing you to display a visual indicator during data loading operations to enhance user experience. */ class LoadingIndicator extends ChildProperty { } __decorate$1([ Property('Spinner') ], LoadingIndicator.prototype, "indicatorType", void 0); var __decorate$2 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; /** * Represents the filter configuration for a column in the TreeGrid. */ class Predicate extends ChildProperty { } __decorate$2([ Property() ], Predicate.prototype, "field", void 0); __decorate$2([ Property() ], Predicate.prototype, "operator", void 0); __decorate$2([ Property() ], Predicate.prototype, "value", void 0); __decorate$2([ Property() ], Predicate.prototype, "matchCase", void 0); __decorate$2([ Property() ], Predicate.prototype, "ignoreAccent", void 0); __decorate$2([ Property() ], Predicate.prototype, "predicate", void 0); __decorate$2([ Property({}) ], Predicate.prototype, "actualFilterValue", void 0); __decorate$2([ Property({}) ], Predicate.prototype, "actualOperator", void 0); __decorate$2([ Property() ], Predicate.prototype, "type", void 0); __decorate$2([ Property() ], Predicate.prototype, "ejpredicate", void 0); __decorate$2([ Property() ], Predicate.prototype, "uid", void 0); __decorate$2([ Property() ], Predicate.prototype, "isForeignKey", void 0); /** * Configures the filtering behavior of the TreeGrid, enabling complex data filtering capabilities. */ class FilterSettings extends ChildProperty { } __decorate$2([ Collection([], Predicate) ], FilterSettings.prototype, "columns", void 0); __decorate$2([ Property('FilterBar') ], FilterSettings.prototype, "type", void 0); __decorate$2([ Property() ], FilterSettings.prototype, "mode", void 0); __decorate$2([ Property(true) ], FilterSettings.prototype, "showFilterBarStatus", void 0); __decorate$2([ Property(1500) ], FilterSettings.prototype, "immediateModeDelay", void 0); __decorate$2([ Property() ], FilterSettings.prototype, "operators", void 0); __decorate$2([ Property(false) ], FilterSettings.prototype, "ignoreAccent", void 0); __decorate$2([ Property('Parent') ], FilterSettings.prototype, "hierarchyMode", void 0); var __decorate$3 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; /** * Configures the text wrapping behavior of the TreeGrid. */ class TextWrapSettings extends ChildProperty { } __decorate$3([ Property('Both') ], TextWrapSettings.prototype, "wrapMode", void 0); /** * Logger module for TreeGrid * * @hidden */ const DOC_URL = 'https://ej2.syncfusion.com/documentation/treegrid'; const BASE_DOC_URL = 'https://ej2.syncfusion.com/documentation'; const ERROR = '[EJ2TreeGrid.Error]'; let IsRowDDEnabled = false; class Logger extends Logger$1 { constructor(parent) { Grid.Inject(Logger$1); super(parent); } /** * For internal use only - Get the module name. * * @private * @returns {string} - Returns Logger module name */ getModuleName() { return 'logger'; } log(types, args) { if (!(types instanceof Array)) { types = [types]; } const type = types; for (let i = 0; i < type.length; i++) { const item = detailLists[type[parseInt(i.toString(), 10)]]; const cOp = item.check(args, this.parent); if (cOp.success) { let message = item.generateMessage(args, this.parent, cOp.options); message = message.replace('EJ2Grid', 'EJ2TreeGrid').replace('* Hierarchy Grid', '').replace('* Grouping', ''); if (IsRowDDEnabled && type[parseInt(i.toString(), 10)] === 'primary_column_missing') { message = message.replace('Editing', 'Row DragAndDrop'); IsRowDDEnabled = false; } const index = message.indexOf('https'); const gridurl = message.substring(index); if (type[parseInt(i.toString(), 10)] === 'module_missing') { message = message.replace(gridurl, DOC_URL + '/modules'); } else if (type[parseInt(i.toString(), 10)] === 'primary_column_missing' || type[parseInt(i.toString(), 10)] === 'selection_key_missing') { message = message.replace(gridurl, BASE_DOC_URL + '/api/treegrid/column/#isprimarykey'); } else if (type[parseInt(i.toString(), 10)] === 'grid_remote_edit') { message = message.replace(gridurl, DOC_URL + '/edit'); } else if (type[parseInt(i.toString(), 10)] === 'virtual_height') { message = message.replace(gridurl, DOC_URL + '/virtual'); } else if (type[parseInt(i.toString(), 10)] === 'check_datasource_columns') { message = message.replace(gridurl, DOC_URL + '/columns'); } else if (type[parseInt(i.toString(), 10)] === 'locale_missing') { message = message.replace(gridurl, DOC_URL + '/global-local/#localization'); } if (type[parseInt(i.toString(), 10)] === 'datasource_syntax_mismatch') { if (!isNullOrUndefined(this.treeGridObj) && !isNullOrUndefined(this.treeGridObj.dataStateChange)) { // eslint-disable-next-line no-console console[item.logType](message); } } else { // eslint-disable-next-line no-console console[item.logType](message); } } } } treeLog(types, args, treeGrid) { this.treeGridObj = treeGrid; if (!(types instanceof Array)) { types = [types]; } const type = types; if (treeGrid.allowRowDragAndDrop && !treeGrid.columns.filter((column) => column.isPrimaryKey).length) { IsRowDDEnabled = true; this.log('primary_column_missing', args); } for (let i = 0; i < type.length; i++) { const item = treeGridDetails[type[parseInt(i.toString(), 10)]]; const cOp = item.check(args, treeGrid); if (cOp.success) { const message = item.generateMessage(args, treeGrid, cOp.options); // eslint-disable-next-line no-console console[item.logType](message); } } } } const treeGridDetails = { // eslint-disable-next-line camelcase mapping_fields_missing: { type: 'mapping_fields_missing', logType: 'error', check(args, parent) { let opt = { success: false }; if ((isNullOrUndefined(parent.idMapping) && isNullOrUndefined(parent.childMapping) && isNullOrUndefined(parent.parentIdMapping)) || (!isNullOrUndefined(parent.idMapping) && isNullOrUndefined(parent.parentIdMapping)) || (isNullOrUndefined(parent.idMapping) && !isNullOrUndefined(parent.parentIdMapping))) { opt = { success: true }; } return opt; }, generateMessage() { return ERROR + ':' + ' MAPPING FIELDS MISSING \n' + 'One of the following fields is missing. It is ' + 'required for the hierarchical relationship of records in TreeGrid:\n' + '* childMapping\n' + '* idMapping\n' + '* parentIdMapping\n' + 'Refer to the following documentation links for more details.\n' + `${BASE_DOC_URL}/api/treegrid#childmapping` + '\n' + `${BASE_DOC_URL}/api/treegrid#idmapping` + '\n' + `${BASE_DOC_URL}/api/treegrid#$parentidmapping`; } } }; /** * @hidden */ const load = 'load'; /** @hidden */ const rowDataBound = 'rowDataBound'; /** @hidden */ const dataBound = 'dataBound'; /** @hidden */ const queryCellInfo = 'queryCellInfo'; /** @hidden */ const beforeDataBound = 'beforeDataBound'; /** @hidden */ const actionBegin = 'actionBegin'; /** @hidden */ const dataStateChange = 'dataStateChange'; /** @hidden */ const actionComplete = 'actionComplete'; /** @hidden */ const rowSelecting = 'rowSelecting'; /** @hidden */ const rowSelected = 'rowSelected'; /** @hidden */ const checkboxChange = 'checkboxChange'; /** @hidden */ const rowDeselected = 'rowDeselected'; /** @hidden */ const toolbarClick = 'toolbarClick'; /** @hidden */ const beforeExcelExport = 'beforeExcelExport'; /** @hidden */ const beforePdfExport = 'beforePdfExport'; /** @hidden */ const resizeStop = 'resizeStop'; /** @hidden */ const expanded = 'expanded'; /** @hidden */ const expanding = 'expanding'; /** @hidden */ const collapsed = 'collapsed'; /** @hidden */ const collapsing = 'collapsing'; /** @hidden */ const remoteExpand = 'remoteExpand'; /** @hidden */ const localPagedExpandCollapse = 'localPagedExpandCollapse'; /** @hidden */ const pagingActions = 'pagingActions'; /** @hidden */ const printGridInit = 'printGrid-Init'; /** @hidden */ const contextMenuOpen = 'contextMenuOpen'; /** @hidden */ const contextMenuClick = 'contextMenuClick'; /** @hidden */ const beforeCopy = 'beforeCopy'; /** @hidden */ const beforePaste = 'beforePaste'; /** @hidden */ const savePreviousRowPosition = 'savePreviousRowPosition'; /** @hidden */ const crudAction = 'crudAction'; /** @hidden */ const beginEdit = 'beginEdit'; /** @hidden */ const beginAdd = 'beginAdd'; /** @hidden */ const recordDoubleClick = 'recordDoubleClick'; /** @hidden */ const cellSave = 'cellSave'; /** @hidden */ const cellSaved = 'cellSaved'; /** @hidden */ const cellEdit = 'cellEdit'; /** @hidden */ const batchDelete = 'batchDelete'; /** @hidden */ const batchCancel = 'batchCancel'; /** @hidden */ const batchAdd = 'batchAdd'; /** @hidden */ const beforeBatchDelete = 'beforeBatchDelete'; /** @hidden */ const beforeBatchAdd = 'beforeBatchAdd'; /** @hidden */ const beforeBatchSave = 'beforeBatchSave'; /** @hidden */ const batchSave = 'batchSave'; /** @hidden */ const keyPressed = 'key-pressed'; /** @hidden */ const updateData = 'update-data'; /** @hidden */ const doubleTap = 'double-tap'; /** @hidden */ const virtualColumnIndex = 'virtualColumnIndex'; /** @hidden */ const virtualActionArgs = 'virtual-action-args'; /** @hidden */ const destroy = 'destroy'; /** @hidden */ const dataListener = 'data-listener'; /** @hidden */ const indexModifier = 'index-modifier'; /** @hidden */ const beforeStartEdit = 'edit-form'; /** @hidden */ const beforeBatchCancel = 'before-batch-cancel'; /** @hidden */ const batchEditFormRendered = 'batcheditform-rendered'; /** @hidden */ const detailDataBound = 'detailDataBound'; /** @hidden */ const rowDrag = 'rowDrag'; /** @hidden */ const rowDragStartHelper = 'rowDragStartHelper'; /** @hidden */ const rowDrop = 'rowDrop'; /** @hidden */ const rowDragStart = 'rowDragStart'; /** @hidden */ const rowsAdd = 'rows-add'; /** @hidden */ const rowsRemove = 'rows-remove'; /** @hidden */ const rowdraging = 'row-draging'; /** @hidden */ const rowDropped = 'row-dropped'; /** @hidden */ const autoCol = 'auto-col'; /** @hidden */ const rowDeselecting = 'rowDeselecting'; /** @hidden */ const headerContent = 'e-headercontent'; /** @hidden */ const movableContent = 'e-movablecontent'; /** @hidden */ const movableHeader = 'e-movableheader'; /** @hidden */ const frozenContent = 'e-frozencontent'; /** @hidden */ const frozenHeader = 'e-frozenheader'; /** @hidden */ const content = 'e-content'; /** @hidden */ const table = 'e-table'; /** @hidden */ const leftRight = 'Left-Right'; /** @hidden */ const frozenRight = 'frozen-right'; /** @hidden */ const frozenLeft = 'frozen-left'; /** @hidden */ const ariaColIndex = 'aria-colindex'; /** @hidden */ const ariaRowIndex = 'aria-rowindex'; /** @hidden */ const actionFailure = 'actionFailure'; /** * The `Clipboard` module is used to handle clipboard copy action. * * @hidden */ class TreeClipboard extends Clipboard { constructor(parent, serviceLocator) { super(parent.grid, serviceLocator); this.treeCopyContent = ''; this.copiedUniqueIdCollection = []; this.treeGridParent = parent; this.serviceLocator = serviceLocator; } setCopyData(withHeader) { const copyContent = 'copyContent'; const getCopyData = 'getCopyData'; const isSelect = 'isSelect'; const uniqueID = 'uniqueID'; const currentRecords = this.treeGridParent.getCurrentViewRecords(); if (window.getSelection().toString() === '') { this.clipBoardTextArea.value = this[`${copyContent}`] = ''; const rows = this.treeGridParent.grid.getRows(); if (this.treeGridParent.selectionSettings.mode !== 'Cell') { const selectedIndexes = this.treeGridParent.getSelectedRowIndexes().sort((a, b) => { return a - b; }); for (let i = 0; i < selectedIndexes.length; i++) { if (i > 0) { this.treeCopyContent += '\n'; } const selectedRowIndex = selectedIndexes[parseInt(i.toString(), 10)]; if (!rows[selectedRowIndex].classList.contains('e-summaryrow')) { const cells = [].slice.call(rows[selectedRowIndex].querySelectorAll('.e-rowcell')); const uniqueid = this.treeGridParent.getSelectedRecords()[parseInt(i.toString(), 10)][`${uniqueID}`]; if (this.copiedUniqueIdCollection.indexOf(uniqueid) === -1) { if (this.treeGridParent.copyHierarchyMode === 'Parent' || this.treeGridParent.copyHierarchyMode === 'Both') { this.parentContentData(currentRecords, selectedRowIndex, rows, withHeader, i); } this[`${getCopyData}`](cells, false, '\t', withHeader); this.treeCopyContent += this[`${copyContent}`]; this.copiedUniqueIdCollection.push(uniqueid); this[`${copyContent}`] = ''; if (this.treeGridParent.copyHierarchyMode === 'Child' || this.treeGridParent.copyHierarchyMode === 'Both') { this.childContentData(currentRecords, selectedIndexes[parseInt(i.toString(), 10)], rows, withHeader); } } } } if (withHeader) { const headerTextArray = this.treeGridParent.getVisibleColumns().map((col) => col.headerText); this[`${getCopyData}`](headerTextArray, false, '\t', withHeader); this.treeCopyContent = this[`${copyContent}`] + '\n' + this.treeCopyContent; } const args = { data: this.treeCopyContent, cancel: false }; this.treeGridParent.trigger(beforeCopy, args); if (args.cancel) { return; } this.clipBoardTextArea.value = this[`${copyContent}`] = args.data; if (!Browser.userAgent.match(/ipad|ipod|iphone/i)) { this.clipBoardTextArea.select(); } else { this.clipBoardTextArea.setSelectionRange(0, this.clipBoardTextArea.value.length); } this[`${isSelect}`] = true; this.copiedUniqueIdCollection = []; this.treeCopyContent = ''; } else { super.setCopyData(withHeader); } } } parentContentData(currentRecords, selectedIndex, rows, withHeader, index) { const getCopyData = 'getCopyData'; const copyContent = 'copyContent'; const parentItem = 'parentItem'; const uniqueID = 'uniqueID'; const level = 'level'; if (!isNullOrUndefined(currentRecords[parseInt(selectedIndex.toString(), 10)][`${parentItem}`])) { const treeLevel = currentRecords[parseInt(selectedIndex.toString(), 10)][`${parentItem}`][`${level}`]; for (let i = 0; i < treeLevel + 1; i++) { for (let j = 0; j < currentRecords.length; j++) { if (!isNullOrUndefined(currentRecords[parseInt(selectedIndex.toString(), 10)][`${parentItem}`]) && currentRecords[parseInt(j.toString(), 10)][`${uniqueID}`] === currentRecords[parseInt(selectedIndex.toString(), 10)][`${parentItem}`][`${uniqueID}`]) { selectedIndex = j; const cells = [].slice.call(rows[parseInt(selectedIndex.toString(), 10)].querySelectorAll('.e-rowcell')); const uniqueid = currentRecords[parseInt(j.toString(), 10)][`${uniqueID}`]; if (this.copiedUniqueIdCollection.indexOf(uniqueid) === -1) { this[`${getCopyData}`](cells, false, '\t', withHeader); if (index > 0) { this.treeCopyContent = this.treeCopyContent + this[`${copyContent}`] + '\n'; } else { this.treeCopyContent = this[`${copyContent}`] + '\n' + this.treeCopyContent; } this.copiedUniqueIdCollection.push(uniqueid); this[`${copyContent}`] = ''; break; } } } } } } copy(withHeader) { super.copy(withHeader); } paste(data, rowIndex, colIndex) { super.paste(data, rowIndex, colIndex); } /** * For internal use only - Get the module name. * * @private * @returns {string} Returns clipboard module name */ getModuleName() { return 'clipboard'; } /** * To destroy the clipboard * * @returns {void} * @hidden */ destroy() { super.destroy(); } childContentData(currentRecords, selectedIndex, rows, withHeader) { const getCopyData = 'getCopyData'; const copyContent = 'copyContent'; const childRecords = 'childRecords'; const hasChildRecords = 'hasChildRecords'; const uniqueID = 'uniqueID'; if (currentRecords[parseInt(selectedIndex.toString(), 10)][`${hasChildRecords}`]) { const childData = currentRecords[parseInt(selectedIndex.toString(), 10)][`${childRecords}`]; for (let i = 0; i < childData.length; i++) { for (let j = 0; j < currentRecords.length; j++) { if (!isNullOrUndefined(childData[parseInt(i.toString(), 10)][`${uniqueID}`]) && currentRecords[parseInt(j.toString(), 10)][`${uniqueID}`] === childData[parseInt(i.toString(), 10)][`${uniqueID}`]) { if ((!isNullOrUndefined(rows[parseInt(j.toString(), 10)])) && !rows[parseInt(j.toString(), 10)].classList.contains('e-summaryrow')) { const cells = [].slice.call(rows[parseInt(j.toString(), 10)].querySelectorAll('.e-rowcell')); const uniqueid = currentRecords[parseInt(j.toString(), 10)][`${uniqueID}`]; if (this.copiedUniqueIdCollection.indexOf(uniqueid) === -1) { this[`${getCopyData}`](cells, false, '\t', withHeader); this.treeCopyContent += ('\n' + this[`${copyContent}`]); this[`${copyContent}`] = ''; this.copiedUniqueIdCollection.push(uniqueid); this.childContentData(currentRecords, j, rows, withHeader); } } break; } } } } } } /** * @param {TreeGrid} parent - Tree Grid instance * @returns {boolean} - Specifies whether remote data binding */ function isRemoteData(parent) { if (parent.dataSource instanceof DataManager) { const adaptor = parent.dataSource.adaptor; return (adaptor instanceof ODataAdaptor || (adaptor instanceof WebApiAdaptor) || (adaptor instanceof WebMethodAdaptor) || (adaptor instanceof CacheAdaptor) || adaptor instanceof UrlAdaptor); } return false; } /** * @param {TreeGrid | IGrid} parent - Tree Grid or Grid instance * @returns {boolean} - Returns whether custom binding */ function isCountRequired(parent) { if (parent.dataSource && 'result' in parent.dataSource) { return true; } return false; } /** * @param {TreeGrid} parent - Tree Grid instance * @returns {boolean} - Returns whether checkbox column is enabled */ function isCheckboxcolumn(parent) { for (let i = 0; i < parent.columns.length; i++) { if (parent.columns[parseInt(i.toString(), 10)].showCheckbox) { return true; } } return false; } /** * @param {TreeGrid} parent - Tree Grid instance * @returns {boolean} - Returns whether filtering and searching done */ function isFilterChildHierarchy(parent) { if ((!isNullOrUndefined(parent.grid.searchSettings.key) && parent.grid.searchSettings.key !== '' && (parent.searchSettings.hierarchyMode === 'Child' || parent.searchSettings.hierarchyMode === 'None')) || (parent.allowFiltering && parent.grid.filterSettings.columns.length && (parent.filterSettings.hierarchyMode === 'Child' || parent.filterSettings.hierarchyMode === 'None'))) { return true; } return false; } /** * @param {Object} records - Define records for which parent records has to be found * @hidden * @returns {Object} - Returns parent records collection */ function findParentRecords(records) { const datas = []; const recordsLength = Object.keys(records).length; for (let i = 0, len = recordsLength; i < len; i++) { const hasChild = getObject('hasChildRecords', records[parseInt(i.toString(), 10)]); if (hasChild) { datas.push(records[parseInt(i.toString(), 10)]); } } return datas; } /** * @param {TreeGrid} parent - Tree Grid instance * @returns {boolean} - Returns the expand status of record * @param {ITreeData} record - Define the record for which expand status has be found * @param {ITreeData[]} parents - Parent Data collection * @hidden */ function getExpandStatus(parent, record, parents) { const parentRecord = isNullOrUndefined(record.parentItem) ? null : getParentData(parent, record.parentItem.uniqueID); let childParent; if (parentRecord != null) { if (parent.initialRender && !isNullOrUndefined(parentRecord[parent.expandStateMapping]) && !parentRecord[parent.expandStateMapping]) { parentRecord.expanded = false; return false; } else if (parentRecord.expanded === false) { return false; } else if (parentRecord.parentItem) { childParent = getParentData(parent, parentRecord.parentItem.uniqueID); if (childParent && parent.initialRender && !isNullOrUndefined(childParent[parent.expandStateMapping]) && !childParent[parent.expandStateMapping]) { childParent.expanded = false; return false; } if (childParent && childParent.expanded === false) { return false; } else if (childParent) { return getExpandStatus(parent, childParent); } return true; } else { return true; } } else { return true; } } /** * @param {ITreeData} records - Define the record for which child records has to be found * @returns {Object[]} - Returns child records collection * @hidden */ function findChildrenRecords(records) { let datas = []; if (isNullOrUndefined(records) || (!records.hasChildRecords && !isNullOrUndefined(records.childRecords) && !records.childRecords.length)) { return []; } if (!isNullOrUndefined(records.childRecords)) { const childRecords = records.childRecords.filter((item) => !item.isSummaryRow); const keys = Object.keys(childRecords); for (let i = 0, len = keys.length; i < len; i++) { datas.push(childRecords[parseInt(i.toString(), 10)]); if (childRecords[parseInt(i.toString(), 10)].hasChildRecords || (!isNullOrUndefined(childRecords[parseInt(i.toString(), 10)].childRecords) && childRecords[parseInt(i.toString(), 10)].childRecords.length)) { datas = [...datas, ...findChildrenRecords(childRecords[parseInt(i.toString(), 10)])]; } } } return datas; } /** * @param {TreeGrid} parent - Tree Grid instance * @returns {boolean} - Returns whether local data binding */ function isOffline(parent) { if (isRemoteData(parent)) { const dm = parent.dataSource; return !isNullOrUndefined(dm.ready); } return true; } /** * @param {Object[]} array - Defines the array to be cloned * @returns {Object[]} - Returns cloned array collection */ function extendArray(array) { const objArr = []; let obj; let keys; for (let i = 0; array && i < array.length; i++) { keys = Object.keys(array[parseInt(i.toString(), 10)]); obj = {}; for (let j = 0; j < keys.length; j++) { obj[keys[parseInt(j.toString(), 10)]] = array[parseInt(i.toString(), 10)][keys[parseInt(j.toString(), 10)]]; } objArr.push(obj); } return objArr; } /** * @param {ITreeData} value - Defined the dirty data to be cleaned * @returns {ITreeData} - Returns cleaned original data */ function getPlainData(value) { delete value.hasChildRecords; delete value.childRecords; delete value.index; delete value.parentItem; delete value.level; delete value.taskData; delete value.uniqueID; return value; } /** * @param {TreeGrid} parent - TreeGrid instance * @param {string} value - IdMapping field name * @param {boolean} requireFilter - Specified whether treegrid data is filtered * @returns {ITreeData} - Returns IdMapping matched record */ function getParentData(parent, value, requireFilter) { if (requireFilter) { const idFilter = 'uniqueIDFilterCollection'; return parent[`${idFilter}`][`${value}`]; } else { const id = 'uniqueIDCollection'; return parent[`${id}`][`${value}`]; } } /** * @param {HTMLTableRowElement} el - Row element * @returns {boolean} - Returns whether hidden */ function isHidden(el) { const style = window.getComputedStyle(el); return ((style.display === 'none') || (style.visibility === 'hidden')); } /** * TreeGrid Selection module * * @hidden */ class Selection { /** * Constructor for Selection module * * @param {TreeGrid} parent - Tree Grid instance */ constructor(parent) { this.parent = parent; this.selectedItems = []; this.selectedIndexes = []; this.filteredList = []; this.searchingRecords = []; this.addEventListener(); } /** * For internal use only - Get the module name. * * @private * @returns {string} Returns Selection module name */ getModuleName() { return 'selection'; } addEventListener() { this.parent.on('dataBoundArg', this.headerCheckbox, this); this.parent.on('columnCheckbox', this.columnCheckbox, this); this.parent.on('updateGridActions', this.updateGridActions, this); this.parent.grid.on('colgroup-refresh', this.headerCheckbox, this); this.parent.on('checkboxSelection', this.checkboxSelection, this); } removeEventListener() { if (this.parent.isDestroyed) { return; } this.parent.off('dataBoundArg', this.headerCheckbox); this.parent.off('columnCheckbox', this.columnCheckbox); this.parent.grid.off('colgroup-refresh', this.headerCheckbox); this.parent.off('checkboxSelection', this.checkboxSelection); this.parent.off('updateGridActions', this.updateGridActions); } /** * To destroy the Selection * * @returns {void} * @hidden */ destroy() { this.removeEventListener(); } checkboxSelection(args) { const target = getObject('target', args); const checkWrap = parentsUntil(target, 'e-checkbox-wrapper'); let checkBox; if (checkWrap && checkWrap.querySelectorAll('.e-treecheckselect').length > 0) { checkBox = checkWrap.querySelector('input[type="checkbox"]'); const rowIndex = []; rowIndex.push(target.closest('tr').rowIndex); this.selectCheckboxes(rowIndex); this.triggerChkChangeEvent(checkBox, checkBox.nextElementSibling.classList.contains('e-check'), target.closest('tr')); } else if (checkWrap && checkWrap.querySelectorAll('.e-treeselectall').length > 0 && this.parent.autoCheckHierarchy) { const checkBoxvalue = !checkWrap.querySelector('.e-frame').classList.contains('e-check') && !checkWrap.querySelector('.e-frame').classList.contains('e-stop'); this.headerSelection(checkBoxvalue); checkBox = checkWrap.querySelector('input[type="checkbox"]'); this.triggerChkChangeEvent(checkBox, checkBoxvalue, target.closest('tr')); } if (!isNullOrUndefined(this.parent['parentQuery']) && this.parent.selectionSettings.persistSelection && this.parent['columnModel'].filter((col) => { return col.type === 'checkbox'; }).length > 0 && isRemoteData(this.parent)) { if (this.parent['parentQuery'].length > 0) { this.parent.query.queries.push(...this.parent['parentQuery']); this.parent['parentQuery'] = []; } } } triggerChkChangeEvent(checkBox, checkState, rowElement) { const data = this.parent.getCurrentViewRecords()[rowElement.rowIndex]; const args = { checked: checkState, target: checkBox, rowElement: rowElement, rowData: checkBox.classList.contains('e-treeselectall') ? this.parent.getCheckedRecords() : data }; this.parent.trigger(checkboxChange, args); } getCheckboxcolumnIndex() { let mappingUid; let columnIndex; const stackedHeader = 'stackedHeader'; const columnModel = 'columnModel'; const columns = this.parent[`${stackedHeader}`] ? this.parent[`${columnModel}`] : (this.parent.columns); for (let col = 0; col < columns.length; col++) { if (columns[parseInt(col.toString(), 10)].showCheckbox) { mappingUid = columns[parseInt(col.toString(), 10)].uid; } } const headerCelllength = this.parent.getHeaderContent().querySelectorAll('.e-headercelldiv').length; for (let j = 0; j < headerCelllength; j++) { const headercell = this.parent.getHeaderContent().querySelectorAll('.e-headercelldiv')[parseInt(j.toString(), 10)]; if (headercell.getAttribute('e-mappinguid') === mappingUid) { columnIndex = j; } } return columnIndex; } headerCheckbox() { this.columnIndex = this.getCheckboxcolumnIndex(); if (this.columnIndex > -1 && this.parent.getHeaderContent().querySelectorAll('.e-treeselectall').length === 0) { const headerElement = this.parent.getHeaderContent().querySelectorAll('.e-headercelldiv')[this.columnIndex]; const value = false; const rowChkBox = this.parent.createElement('input', { className: 'e-treeselectall', attrs: { 'type': 'checkbox' } }); const checkWrap = createCheckBox(this.parent.createElement, false, { checked: value, label: ' ' }); checkWrap.classList.add('e-hierarchycheckbox'); checkWrap.insertBefore(rowChkBox.cloneNode(), checkWrap.firstChild); if (!isNullOrUndefined(headerElement)) { headerElement.insertBefore(checkWrap, headerElement.firstChild); } if (this.parent.autoCheckHierarchy) { this.headerSelection(); } } else if (this.columnIndex > -1 && this.parent.getHeaderContent().querySelectorAll('.e-treeselectall').length > 0) { const checkWrap = this.parent.getHeaderContent().querySelectorAll('.e-checkbox-wrapper')[0]; const checkBoxvalue = checkWrap.querySelector('.e-frame').classList.contains('e-check'); if (this.parent.autoCheckHierarchy && checkBoxvalue) { this.headerSelection(checkBoxvalue); } } } renderColumnCheckbox(args) { const rowChkBox = this.parent.createElement('input', { className: 'e-treecheckselect', attrs: { 'type': 'checkbox', 'aria-label': 'checkbox' } }); const data = args.data; args.cell.classList.add('e-treegridcheckbox'); args.cell.setAttribute('aria-label', 'checkbox'); const value = (isNullOrUndefined(data.checkboxState) || data.checkboxState === 'uncheck') ? false : true; const checkWrap = createCheckBox(this.parent.createElement, false, { checked: value, label: ' ' }); checkWrap.classList.add('e-hierarchycheckbox'); if (this.parent.allowTextWrap) { checkWrap.querySelector('.e-frame').style.width = '18px'; } if (data.checkboxState === 'indeterminate') { const checkbox = checkWrap.querySelectorAll('.e-frame')[0]; removeClass([checkbox], ['e-check', 'e-stop', 'e-uncheck']); checkWrap.querySelector('.e-frame').classList.add('e-stop'); } checkWrap.insertBefore(rowChkBox.cloneNode(), checkWrap.firstChild); return checkWrap; } columnCheckbox(container) { const checkWrap = this.renderColumnCheckbox(container); const containerELe = container.cell.querySelector('.e-treecolumn-container'); if (!isNullOrUndefined(containerELe)) { if (!container.cell.querySelector('.e-hierarchycheckbox')) { containerELe.insertBefore(checkWrap, containerELe.querySelectorAll('.e-treecell')[0]); } } else { const spanEle = this.parent.createElement('span', { className: 'e-treecheckbox' }); const data = container.cell.innerHTML; container.cell.innerHTML = ''; spanEle.innerHTML = data; const divEle = this.parent.createElement('div', { className: 'e-treecheckbox-container' }); divEle.appendChild(checkWrap); divEle.appendChild(spanEle); container.cell.appendChild(divEle); } } selectCheckboxes(rowIndexes) { if (isNullOrUndefined(rowIndexes)) { const error = 'The provided value for the rowIndexes is undefined. Please ensure the rowIndexes contains number.'; this.parent.trigger(actionFailure, { error: error }); } for (let i = 0; i < rowIndexes.length; i++) { let record = this.parent.getCurrentViewRecords()[rowIndexes[parseInt(i.toString(), 10)]]; const flatRecord = getParentData(this.parent, record.uniqueID); record = flatRecord; const checkboxState = (record.checkboxState === 'uncheck') ? 'check' : 'uncheck'; record.checkboxState = checkboxState; const keys = Object.keys(record); for (let j = 0; j < keys.length; j++) { if (Object.prototype.hasOwnProperty.call(flatRecord, keys[parseInt(j.toString(), 10)])) { flatRecord[keys[parseInt(j.toString(), 10)]] = record[keys[parseInt(j.toString(), 10)]]; } } this.traverSelection(record, checkboxState, false); if (this.parent.autoCheckHierarchy) { this.headerSelection(); } } } traverSelection(record, checkboxState, ischildItem) { let length = 0; this.updateSelectedItems(record, checkboxState); if (!ischildItem && record.parentItem && this.parent.autoCheckHierarchy) { this.updateParentSelection(record.parentItem); } if (record.childRecords && this.parent.autoCheckHierarchy) { let childRecords = record.childRecords; if (!isNullOrUndefined(this.parent.filterModule) && this.parent.filterModule.filteredResult.length > 0 && this.parent.autoCheckHierarchy) { childRecords = this.getFilteredChildRecords(childRecords); } length = childRecords.length; for (let count = 0; count < length; count++) { if (!childRecords[parseInt(count.toString(), 10)].isSummaryRow) { if (childRecords[parseInt(count.toString(), 10)].hasChildRecords) { this.traverSelection(childRecords[parseInt(count.toString(), 10)], checkboxState, true); } else { this.updateSelectedItems(childRecords[parseInt(count.toString(), 10)], checkboxState); } } } } } getFilteredChildRecords(childRecords) { const filteredChildRecords = childRecords.filter((e) => { return this.parent.filterModule.filteredResult.indexOf(e) > -1; }); return filteredChildRecords; } updateParentSelection(parentRecord) { let length = 0; let childRecords = []; const record = getParentData(this.parent, parentRecord.uniqueID); if (record && record.childRecords) { childRecords = record.childRecords; } if (!isNullOrUndefined(this.parent.filterModule) && this.parent.filterModule.filteredResult.length > 0 && this.parent.autoCheckHierarchy) { childRecords = this.getFilteredChildRecords(childRecords); } length = childRecords && childRecords.length; let indeter = 0; let checkChildRecords = 0; if (!isNullOrUndefined(record)) { for (let i = 0; i < childRecords.length; i++) { const currentRecord = getParentData(this.parent, childRecords[parseInt(i.toString(), 10)].uniqueID); const checkBoxRecord = currentRecord; if (!isNullOrUndefined(checkBoxRecord)) { if (checkBoxRecord.checkboxState === 'indeterminate') { indeter++; } else if (checkBoxRecord.checkboxState === 'check') { checkChildRecords++; } } } if (indeter > 0 || (checkChildRecords > 0 && checkChildRecords !== length)) { record.checkboxState = 'indeterminate'; } else if (checkChildRecords === 0 && (!record.hasFilteredChildRecords || isNullOrUndefined(record.hasFilteredChildRecords)) && !isNullOrUndefined(this.parent['dataResults']['actionArgs']) && (this.parent['dataResults']['actionArgs'].requestType === 'searching' || this.parent['dataResults']['actionArgs'].requestType === 'filtering') && record.checkboxState === 'check') { record.checkboxState = 'check'; } else if ((checkChildRecords === 0 && indeter === 0) || (checkChildRecords === 0 && record.hasFilteredChildRecords && !isNullOrUndefined(this.parent['dataResults']['actionArgs']) && (this.parent['dataResults']['actionArgs'].requestType === 'searching' || this.parent['dataResults']['actionArgs'].requestType === 'filtering') && record.checkboxState === 'check')) { record.checkboxState = 'uncheck'; } else { record.checkboxState = 'check'; } this.updateSelectedItems(record, record.checkboxState); if (record.parentItem) { this.updateParentSelection(record.parentItem); } } } headerSelection(checkAll) { let index = -1; let length = 0; //This property used to maintain the check state of the currentview data after clear filtering let multiFilterCheckState = false; if (!isNullOrUndefined(this.parent.filterModule) && this.parent.filterModule.filteredResult.length > 0) { const filterResult = this.parent.filterModule.filteredResult; if (this.filteredList.length === 0) { this.filteredList = filterResult; } if (this.parent.grid.searchSettings.key.length) { this.searchingRecords = filterResult; } else { if (this.filteredList !== filterResult) { this.filteredList = filterResult; multiFilterCheckState = true; } else { multiFilterCheckState = false; } } } if (this.filteredList.length > 0) { if (!this.parent.filterSettings.columns.length && this.filteredList.length && !this.parent.grid.searchSettings.key.length) { this.filteredList = []; } if (this.searchingRecords.length && !isNullOrUndefined(checkAll)) { this.filteredList = this.searchingRecords; } } let data; if (!(isNullOrUndefined(this.parent.filterModule)) && this.parent.filterModule.filteredResult.length === 0 && this.parent.getCurrentViewRecords().length === 0 && this.parent.filterSettings.columns.length > 0) { data = this.filteredList; } else { data = (!isNullOrUndefined(this.parent.filterModule) && (this.filteredList.length > 0)) ? this.filteredList : this.parent.flatData; } data = isRemoteData(this.parent) ? this.parent.getCurrentViewRecords() : data; if (!isNullOrUndefined(checkAll)) { for (let i = 0; i < data.length; i++) { if (checkAll) { if (data[parseInt(i.toString(), 10)].checkboxState === 'check') { continue; } if (multiFilterCheckState) { continue;