@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
JavaScript
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 };