UNPKG

@syncfusion/ej2-grids

Version:

Feature-rich JavaScript datagrid (datatable) control with built-in support for editing, filtering, grouping, paging, sorting, and exporting to Excel.

536 lines (535 loc) 23.2 kB
import { Browser, EventHandler } from '@syncfusion/ej2-base'; import { extend, isNullOrUndefined } from '@syncfusion/ej2-base'; import { closest, classList } from '@syncfusion/ej2-base'; import { ResponsiveDialogAction } from '../base/enum'; import { setCssInGridPopUp, getActualPropFromColl, isActionPrevent, iterateExtend, parentsUntil } from '../base/util'; import { addRemoveEventListener } from '../base/util'; import * as events from '../base/constant'; import { AriaService } from '../services/aria-service'; import * as literals from '../base/string-literals'; /** * * The `Sort` module is used to handle sorting action. */ var Sort = /** @class */ (function () { /** * Constructor for Grid sorting module * * @param {IGrid} parent - specifies the IGrid * @param {SortSettings} sortSettings - specifies the SortSettings * @param {string[]} sortedColumns - specifies the string * @param {ServiceLocator} locator - specifies the ServiceLocator * @hidden */ function Sort(parent, sortSettings, sortedColumns, locator) { this.contentRefresh = true; this.isModelChanged = true; this.aria = new AriaService(); this.currentTarget = null; this.parent = parent; this.sortSettings = sortSettings; this.sortedColumns = sortedColumns; this.serviceLocator = locator; this.focus = locator.getService('focus'); this.addEventListener(); this.setFullScreenDialog(); } /** * The function used to update sortSettings * * @returns {void} * @hidden */ Sort.prototype.updateModel = function () { var sortedColumn = { field: this.columnName, direction: this.direction }; var index; var gCols = this.parent.groupSettings.columns; var flag = false; if (!this.isMultiSort) { if (!gCols.length) { this.sortSettings.columns = [sortedColumn]; } else { var sortedCols = []; for (var i = 0, len = gCols.length; i < len; i++) { index = this.getSortedColsIndexByField(gCols[parseInt(i.toString(), 10)], sortedCols); if (this.columnName === gCols[parseInt(i.toString(), 10)]) { flag = true; sortedCols.push(sortedColumn); } else { var sCol = this.getSortColumnFromField(gCols[parseInt(i.toString(), 10)]); sortedCols.push({ field: sCol.field, direction: sCol.direction, isFromGroup: sCol.isFromGroup }); } } if (!flag) { sortedCols.push(sortedColumn); } this.sortSettings.columns = sortedCols; } } else { index = this.getSortedColsIndexByField(this.columnName); if (index > -1) { this.sortSettings.columns.splice(index, 1); } this.sortSettings.columns.push(sortedColumn); // eslint-disable-next-line no-self-assign this.sortSettings.columns = this.sortSettings.columns; } this.parent.dataBind(); this.lastSortedCol = this.columnName; }; /** * The function used to trigger onActionComplete * * @param {NotifyArgs} e - specifies the NotifyArgs * @returns {void} * @hidden */ Sort.prototype.onActionComplete = function (e) { var args = !this.isRemove ? { columnName: this.columnName, direction: this.direction, requestType: 'sorting', type: events.actionComplete } : { requestType: 'sorting', type: events.actionComplete }; this.isRemove = false; this.parent.trigger(events.actionComplete, extend(e, args)); }; /** * Sorts a column with the given options. * * @param {string} columnName - Defines the column name to sort. * @param {SortDirection} direction - Defines the direction of sorting field. * @param {boolean} isMultiSort - Specifies whether the previously sorted columns are to be maintained. * @returns {void} */ Sort.prototype.sortColumn = function (columnName, direction, isMultiSort) { var gObj = this.parent; if (this.parent.getColumnByField(columnName).allowSorting === false || this.parent.isContextMenuOpen()) { this.parent.log('action_disabled_column', { moduleName: this.getModuleName(), columnName: columnName }); return; } if (!gObj.allowMultiSorting) { isMultiSort = gObj.allowMultiSorting; } if (this.isActionPrevent()) { gObj.notify(events.preventBatch, { instance: this, handler: this.sortColumn, arg1: columnName, arg2: direction, arg3: isMultiSort }); return; } this.backupSettings(); this.columnName = columnName; this.direction = direction; this.isMultiSort = isMultiSort; this.removeSortIcons(); this.updateSortedCols(columnName, isMultiSort); this.updateModel(); }; Sort.prototype.setFullScreenDialog = function () { if (this.serviceLocator) { this.serviceLocator.registerAdaptiveService(this, this.parent.enableAdaptiveUI, ResponsiveDialogAction.isSort); } }; Sort.prototype.backupSettings = function () { this.lastSortedCols = iterateExtend(this.sortSettings.columns); this.lastCols = this.sortedColumns; }; Sort.prototype.restoreSettings = function () { this.isModelChanged = false; this.isMultiSort = true; this.parent.setProperties({ sortSettings: { columns: this.lastSortedCols } }, true); //this.parent.sortSettings.columns = this.lastSortedCols; this.sortedColumns = this.lastCols; this.isModelChanged = true; }; Sort.prototype.updateSortedCols = function (columnName, isMultiSort) { if (!isMultiSort) { if (this.parent.allowGrouping) { for (var i = 0, len = this.sortedColumns.length; i < len; i++) { if (this.parent.groupSettings.columns.indexOf(this.sortedColumns[parseInt(i.toString(), 10)]) < 0) { this.sortedColumns.splice(i, 1); len--; i--; } } } else { this.sortedColumns.splice(0, this.sortedColumns.length); } } if (this.sortedColumns.indexOf(columnName) < 0) { this.sortedColumns.push(columnName); } }; /** * @param {NotifyArgs} e - specifies the NotifyArgs * @returns {void} * @hidden */ Sort.prototype.onPropertyChanged = function (e) { if (e.module !== this.getModuleName()) { return; } if (this.contentRefresh) { var args = this.sortSettings.columns.length ? { columnName: this.columnName, direction: this.direction, requestType: 'sorting', type: events.actionBegin, target: this.currentTarget, cancel: false } : { requestType: 'sorting', type: events.actionBegin, cancel: false, target: this.currentTarget }; this.parent.notify(events.modelChanged, args); } this.refreshSortSettings(); this.removeSortIcons(); this.addSortIcons(); }; Sort.prototype.refreshSortSettings = function () { this.sortedColumns.length = 0; var sortColumns = this.sortSettings.columns; for (var i = 0; i < sortColumns.length; i++) { if (!sortColumns[parseInt(i.toString(), 10)].isFromGroup) { this.sortedColumns.push(sortColumns[parseInt(i.toString(), 10)].field); } } }; /** * Clears all the sorted columns of the Grid. * * @returns {void} */ Sort.prototype.clearSorting = function () { var cols = getActualPropFromColl(this.sortSettings.columns); if (this.isActionPrevent()) { this.parent.notify(events.preventBatch, { instance: this, handler: this.clearSorting }); return; } for (var i = 0, len = cols.length; i < len; i++) { this.removeSortColumn(cols[parseInt(i.toString(), 10)].field); } }; Sort.prototype.isActionPrevent = function () { return isActionPrevent(this.parent); }; /** * Remove sorted column by field name. * * @param {string} field - Defines the column field name to remove sort. * @returns {void} * @hidden */ Sort.prototype.removeSortColumn = function (field) { var gObj = this.parent; var cols = this.sortSettings.columns; if (cols.length === 0 && this.sortedColumns.indexOf(field) < 0) { return; } if (this.isActionPrevent()) { this.parent.notify(events.preventBatch, { instance: this, handler: this.removeSortColumn, arg1: field }); return; } this.backupSettings(); this.removeSortIcons(); var args = { requestType: 'sorting', type: events.actionBegin, target: this.currentTarget }; for (var i = 0, len = cols.length; i < len; i++) { if (cols[parseInt(i.toString(), 10)].field === field) { if (gObj.allowGrouping && gObj.groupSettings.columns.indexOf(cols[parseInt(i.toString(), 10)].field) > -1) { continue; } this.sortedColumns.splice(this.sortedColumns.indexOf(cols[parseInt(i.toString(), 10)].field), 1); cols.splice(i, 1); this.isRemove = true; if (this.isModelChanged) { this.parent.notify(events.modelChanged, args); } break; } } if (!args.cancel) { this.addSortIcons(); } }; Sort.prototype.getSortedColsIndexByField = function (field, sortedColumns) { var cols = sortedColumns ? sortedColumns : this.sortSettings.columns; for (var i = 0, len = cols.length; i < len; i++) { if (cols[parseInt(i.toString(), 10)].field === field) { return i; } } return -1; }; /** * For internal use only - Get the module name. * * @returns {string} returns the module name * @private */ Sort.prototype.getModuleName = function () { return 'sort'; }; Sort.prototype.initialEnd = function () { this.parent.off(events.contentReady, this.initialEnd); if (this.parent.getColumns().length && this.sortSettings.columns.length) { var gObj = this.parent; this.contentRefresh = false; this.isMultiSort = this.sortSettings.columns.length > 1; for (var _i = 0, _a = gObj.sortSettings.columns.slice(); _i < _a.length; _i++) { var col = _a[_i]; if (this.sortedColumns.indexOf(col.field) > -1) { this.sortColumn(col.field, col.direction, true); } } this.isMultiSort = false; this.contentRefresh = true; } }; /** * @returns {void} * @hidden */ Sort.prototype.addEventListener = function () { if (this.parent.isDestroyed) { return; } this.evtHandlers = [{ event: events.setFullScreenDialog, handler: this.setFullScreenDialog }, { event: events.renderResponsiveChangeAction, handler: this.renderResponsiveChangeAction }, { event: events.contentReady, handler: this.initialEnd }, { event: events.sortComplete, handler: this.onActionComplete }, { event: events.inBoundModelChanged, handler: this.onPropertyChanged }, { event: events.click, handler: this.clickHandler }, { event: events.headerRefreshed, handler: this.refreshSortIcons }, { event: events.keyPressed, handler: this.keyPressed }, { event: events.cancelBegin, handler: this.cancelBeginEvent }, { event: events.destroy, handler: this.destroy }]; addRemoveEventListener(this.parent, this.evtHandlers, true, this); EventHandler.add(document.body, 'click', this.excelFilterSortAction, this); EventHandler.add(document.body, 'touchend', this.excelFilterSortAction, this); }; /** * @returns {void} * @hidden */ Sort.prototype.removeEventListener = function () { if (this.parent.isDestroyed) { return; } addRemoveEventListener(this.parent, this.evtHandlers, false); EventHandler.remove(document.body, 'click', this.excelFilterSortAction); EventHandler.remove(document.body, 'touchend', this.excelFilterSortAction); }; Sort.prototype.excelFilterSortAction = function (e) { var popUp = parentsUntil(e.target, 'e-grid-popup'); var gridID = this.parent.element.id + '_e-popup'; if (popUp && popUp.id === gridID && parentsUntil(e.target, 'e-excelfilter')) { this.excelFilterSortActionHandler(e); } }; /** * To destroy the sorting * * @returns {void} * @hidden */ Sort.prototype.destroy = function () { this.isModelChanged = false; var gridElement = this.parent.element; if (!gridElement || (!gridElement.querySelector('.' + literals.gridHeader) && !gridElement.querySelector('.' + literals.gridContent))) { return; } if (this.parent.element.querySelector('.e-gridpopup').getElementsByClassName('e-sortdirect').length) { this.parent.element.querySelector('.e-gridpopup').style.display = 'none'; } // eslint-disable-next-line @typescript-eslint/no-explicit-any if (!this.parent.refreshing && (this.parent.isDestroyed || !this.parent.allowSorting)) { this.clearSorting(); } this.isModelChanged = true; this.removeEventListener(); }; Sort.prototype.cancelBeginEvent = function (e) { if (e.requestType === 'sorting') { this.restoreSettings(); this.refreshSortIcons(); this.isMultiSort = true; } }; Sort.prototype.clickHandler = function (e) { var gObj = this.parent; this.currentTarget = null; this.popUpClickHandler(e); var target = closest(e.target, '.e-headercell'); if (target && !e.target.classList.contains('e-grptogglebtn') && !(target.classList.contains('e-resized')) && !e.target.classList.contains('e-rhandler') && !e.target.classList.contains('e-columnmenu') && !e.target.classList.contains('e-filtermenudiv') && !parentsUntil(e.target, 'e-stackedheadercell') && !(gObj.allowSelection && gObj.selectionSettings.allowColumnSelection && e.target.classList.contains('e-headercell'))) { var gObj_1 = this.parent; var colObj = gObj_1.getColumnByUid(target.querySelector('.e-headercelldiv').getAttribute('data-mappinguid')); if (colObj.type !== 'checkbox') { this.initiateSort(target, e, colObj); if (Browser.isDevice) { this.showPopUp(e); } } } if (target) { target.classList.remove('e-resized'); } this.excelFilterSortActionHandler(e); }; Sort.prototype.excelFilterSortActionHandler = function (e) { if (parentsUntil(e.target, 'e-excel-ascending') || parentsUntil(e.target, 'e-excel-descending')) { var colUid = closest(e.target, '.e-filter-popup').getAttribute('data-uid'); var direction = isNullOrUndefined(parentsUntil(e.target, 'e-excel-descending')) ? 'Ascending' : 'Descending'; this.sortColumn(this.parent.getColumnByUid(colUid).field, direction, false); } }; Sort.prototype.keyPressed = function (e) { var ele = e.target; if (!this.parent.isEdit && (e.action === 'enter' || e.action === 'ctrlEnter' || e.action === 'shiftEnter') && closest(ele, '.e-headercell')) { var target = this.focus.getFocusedElement(); if (isNullOrUndefined(target) || !target.classList.contains('e-headercell') || !target.querySelector('.e-headercelldiv')) { return; } var col = this.parent.getColumnByUid(target.querySelector('.e-headercelldiv').getAttribute('data-mappinguid')); this.initiateSort(target, e, col); } }; Sort.prototype.initiateSort = function (target, e, column) { var gObj = this.parent; var field = column.field; this.currentTarget = e.target; var direction = !target.getElementsByClassName('e-ascending').length ? 'Ascending' : 'Descending'; this.isMultiSort = e.ctrlKey || this.enableSortMultiTouch || (navigator.userAgent.indexOf('Mac OS') !== -1 && e.metaKey); if (e.shiftKey || (this.sortSettings.allowUnsort && target.getElementsByClassName('e-descending').length) && !(gObj.groupSettings.columns.indexOf(field) > -1)) { this.removeSortColumn(field); } else { this.sortColumn(field, direction, this.isMultiSort); } }; Sort.prototype.showPopUp = function (e) { var target = closest(e.target, '.e-headercell'); if (this.parent.allowMultiSorting && (!isNullOrUndefined(target) || this.parent.isContextMenuOpen())) { setCssInGridPopUp(this.parent.element.querySelector('.e-gridpopup'), e, 'e-sortdirect e-icons e-icon-sortdirect' + (this.sortedColumns.length > 1 ? ' e-spanclicked' : '')); } }; Sort.prototype.popUpClickHandler = function (e) { var target = e.target; if (closest(target, '.e-headercell') || e.target.classList.contains(literals.rowCell) || closest(target, '.e-gridpopup')) { if (target.classList.contains('e-sortdirect')) { if (!target.classList.contains('e-spanclicked')) { target.classList.add('e-spanclicked'); this.enableSortMultiTouch = true; } else { target.classList.remove('e-spanclicked'); this.enableSortMultiTouch = false; this.parent.element.querySelector('.e-gridpopup').style.display = 'none'; } } } else { this.parent.element.querySelector('.e-gridpopup').style.display = 'none'; } }; Sort.prototype.addSortIcons = function () { var gObj = this.parent; var header; var filterElement; var cols = this.sortSettings.columns; var fieldNames = this.parent.getColumns().map(function (c) { return c.field; }); for (var i = 0, len = cols.length; i < len; i++) { header = gObj.getColumnHeaderByField(cols[parseInt(i.toString(), 10)].field); if (fieldNames.indexOf(cols[parseInt(i.toString(), 10)].field) === -1 || isNullOrUndefined(header)) { continue; } this.aria.setSort(header, (cols[parseInt(i.toString(), 10)].direction).toLowerCase()); if (cols.length > 1) { header.querySelector('.e-headercelldiv').insertBefore(this.parent.createElement('span', { className: 'e-sortnumber', innerHTML: (i + 1).toString() }), header.querySelector('.e-headertext')); } filterElement = header.querySelector('.e-sortfilterdiv'); if (cols[parseInt(i.toString(), 10)].direction === 'Ascending') { classList(filterElement, ['e-ascending', 'e-icon-ascending'], []); } else { classList(filterElement, ['e-descending', 'e-icon-descending'], []); } } }; Sort.prototype.removeSortIcons = function (position) { var gObj = this.parent; var header; var fieldNames = this.parent.getColumns().map(function (c) { return c.field; }); for (var i = position ? position : 0, len = !isNullOrUndefined(position) ? position + 1 : fieldNames.length; i < len; i++) { header = gObj.getColumnHeaderByField(fieldNames[parseInt(i.toString(), 10)]); if (isNullOrUndefined(header) || (gObj.allowGrouping && gObj.groupSettings.columns.indexOf(fieldNames[parseInt(i.toString(), 10)]) > -1 && !header.querySelector('.e-sortfilterdiv'))) { continue; } if (isNullOrUndefined(fieldNames[parseInt(i.toString(), 10)])) { continue; } this.aria.setSort(header, 'none'); classList(header.querySelector('.e-sortfilterdiv'), [], ['e-descending', 'e-icon-descending', 'e-ascending', 'e-icon-ascending']); if (header.querySelector('.e-sortnumber')) { header.querySelector('.e-headercelldiv').removeChild(header.querySelector('.e-sortnumber')); } } }; Sort.prototype.getSortColumnFromField = function (field) { for (var i = 0, len = this.sortSettings.columns.length; i < len; i++) { if (this.sortSettings.columns[parseInt(i.toString(), 10)].field === field) { return this.sortSettings.columns[parseInt(i.toString(), 10)]; } } return false; }; Sort.prototype.updateAriaAttr = function () { var fieldNames = this.parent.getColumns().map(function (c) { return c.field; }); for (var _i = 0, _a = this.sortedColumns; _i < _a.length; _i++) { var col = _a[_i]; if (fieldNames.indexOf(col) === -1) { continue; } var header = this.parent.getColumnHeaderByField(col); this.aria.setSort(header, this.getSortColumnFromField(col).direction); } }; Sort.prototype.refreshSortIcons = function () { this.removeSortIcons(); this.isMultiSort = true; this.removeSortIcons(); this.addSortIcons(); this.isMultiSort = false; this.updateAriaAttr(); }; Sort.prototype.renderResponsiveChangeAction = function (args) { this.responsiveDialogRenderer.action = args.action; }; /** * To show the responsive custom sort dialog * * @param {boolean} enable - specifes dialog open * @returns {void} * @hidden */ Sort.prototype.showCustomSort = function (enable) { this.responsiveDialogRenderer.isCustomDialog = enable; this.responsiveDialogRenderer.showResponsiveDialog(); }; return Sort; }()); export { Sort };