UNPKG

handsontable

Version:

Handsontable is a JavaScript Data Grid available for React, Angular and Vue.

801 lines (763 loc) • 32.5 kB
"use strict"; exports.__esModule = true; require("core-js/modules/es.error.cause.js"); require("core-js/modules/es.array.push.js"); require("core-js/modules/esnext.iterator.constructor.js"); require("core-js/modules/esnext.iterator.every.js"); var _element = require("../../helpers/dom/element"); var _mixed = require("../../helpers/mixed"); var _object = require("../../helpers/object"); var _function = require("../../helpers/function"); var _array = require("../../helpers/array"); var _base = require("../base"); var _translations = require("../../translations"); var _hooks = require("../../core/hooks"); var _columnStatesManager = require("./columnStatesManager"); var _shortcutContexts = require("../../shortcutContexts"); var _utils = require("./utils"); var _domHelpers = require("./domHelpers"); var _rootComparator = require("./rootComparator"); var _sortService = require("./sortService"); var _a11y = require("../../helpers/a11y"); function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); } function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); } const PLUGIN_KEY = exports.PLUGIN_KEY = 'columnSorting'; const PLUGIN_PRIORITY = exports.PLUGIN_PRIORITY = 50; const APPEND_COLUMN_CONFIG_STRATEGY = exports.APPEND_COLUMN_CONFIG_STRATEGY = 'append'; const REPLACE_COLUMN_CONFIG_STRATEGY = exports.REPLACE_COLUMN_CONFIG_STRATEGY = 'replace'; const SHORTCUTS_GROUP = PLUGIN_KEY; (0, _sortService.registerRootComparator)(PLUGIN_KEY, _rootComparator.rootComparator); _hooks.Hooks.getSingleton().register('beforeColumnSort'); _hooks.Hooks.getSingleton().register('afterColumnSort'); /** * Tracks the conflicts between `columnSorting` and `multiColumnSorting` options. * Only one plugin can be enabled for Handsontable instance. Once one of them is enabled, * the other should remain disabled even if it's set to `true`. */ const pluginConflictsState = new WeakMap(); // DIFF - MultiColumnSorting & ColumnSorting: changed configuration documentation. /** * @plugin ColumnSorting * @class ColumnSorting * * @description * This plugin sorts the view by columns (but does not sort the data source!). To enable the plugin, set the * {@link Options#columnSorting} property to the correct value (see the examples below). * * @example * ```js * // as boolean * columnSorting: true * * // as an object with initial sort config (sort ascending for column at index 1) * columnSorting: { * initialConfig: { * column: 1, * sortOrder: 'asc' * } * } * * // as an object which define specific sorting options for all columns * columnSorting: { * sortEmptyCells: true, // true = the table sorts empty cells, false = the table moves all empty cells to the end of the table (by default) * indicator: true, // true = shows indicator for all columns (by default), false = don't show indicator for columns * headerAction: true, // true = allow to click on the headers to sort (by default), false = turn off possibility to click on the headers to sort * compareFunctionFactory: function(sortOrder, columnMeta) { * return function(value, nextValue) { * // Some value comparisons which will return -1, 0 or 1... * } * } * } * * // as an object passed to the `column` property, allows specifying a custom options for the desired column. * // please take a look at documentation of `column` property: https://handsontable.com/docs/Options.html#columns * columns: [{ * columnSorting: { * indicator: false, // disable indicator for the first column, * sortEmptyCells: true, * headerAction: false, // clicks on the first column won't sort * compareFunctionFactory: function(sortOrder, columnMeta) { * return function(value, nextValue) { * return 0; // Custom compare function for the first column (don't sort) * } * } * } * }] * ``` */ var _ColumnSorting_brand = /*#__PURE__*/new WeakSet(); class ColumnSorting extends _base.BasePlugin { constructor() { super(...arguments); /** * Load saved settings or sort by predefined plugin configuration. */ _classPrivateMethodInitSpec(this, _ColumnSorting_brand); /** * Instance of column state manager. * * @private * @type {null|ColumnStatesManager} */ _defineProperty(this, "columnStatesManager", null); /** * Cached column properties from plugin like i.e. `indicator`, `headerAction`. * * @private * @type {null|PhysicalIndexToValueMap} */ _defineProperty(this, "columnMetaCache", null); /** * Main settings key designed for the plugin. * * @private * @type {string} */ _defineProperty(this, "pluginKey", PLUGIN_KEY); /** * Plugin indexes cache. * * @private * @type {null|IndexesSequence} */ _defineProperty(this, "indexesSequenceCache", null); } static get PLUGIN_KEY() { return PLUGIN_KEY; } static get PLUGIN_PRIORITY() { return PLUGIN_PRIORITY; } /** * Checks if the plugin is enabled in the Handsontable settings. This method is executed in {@link Hooks#beforeInit} * hook and if it returns `true` then the {@link ColumnSorting#enablePlugin} method is called. * * @returns {boolean} */ isEnabled() { return !!this.hot.getSettings()[this.pluginKey]; } /** * Enables the plugin functionality for this Handsontable instance. */ enablePlugin() { var _this = this; if (pluginConflictsState.has(this.hot) && pluginConflictsState.get(this.hot) !== this.pluginKey) { this.hot.updateSettings({ [this.pluginKey]: false }); (0, _utils.warnAboutPluginsConflict)(pluginConflictsState.get(this.hot), this.pluginKey); return; } if (this.enabled) { return; } pluginConflictsState.set(this.hot, this.pluginKey); this.columnStatesManager = new _columnStatesManager.ColumnStatesManager(this.hot, `${this.pluginKey}.sortingStates`); this.columnMetaCache = new _translations.PhysicalIndexToValueMap(physicalIndex => { let visualIndex = this.hot.toVisualColumn(physicalIndex); if (visualIndex === null) { visualIndex = physicalIndex; } return this.getMergedPluginSettings(visualIndex); }); this.hot.columnIndexMapper.registerMap(`${this.pluginKey}.columnMeta`, this.columnMetaCache); this.addHook('afterGetColHeader', (column, TH) => _assertClassBrand(_ColumnSorting_brand, this, _onAfterGetColHeader).call(this, column, TH)); this.addHook('beforeOnCellMouseDown', function () { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _assertClassBrand(_ColumnSorting_brand, _this, _onBeforeOnCellMouseDown).call(_this, ...args); }); this.addHook('afterOnCellMouseDown', (event, target) => this.onAfterOnCellMouseDown(event, target)); this.addHook('afterInit', () => _assertClassBrand(_ColumnSorting_brand, this, _loadOrSortBySettings).call(this)); this.addHook('afterLoadData', function () { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } return _assertClassBrand(_ColumnSorting_brand, _this, _onAfterLoadData).call(_this, ...args); }); // TODO: Workaround? It should be refactored / described. if (this.hot.view) { _assertClassBrand(_ColumnSorting_brand, this, _loadOrSortBySettings).call(this); } this.registerShortcuts(); super.enablePlugin(); } /** * Disables the plugin functionality for this Handsontable instance. */ disablePlugin() { const clearColHeader = (column, TH) => { const headerSpanElement = (0, _utils.getHeaderSpanElement)(TH); if ((0, _utils.isFirstLevelColumnHeader)(column, TH) === false || headerSpanElement === null) { return; } this.updateHeaderClasses(headerSpanElement); }; pluginConflictsState.delete(this.hot); // Changing header width and removing indicator. this.hot.addHook('afterGetColHeader', clearColHeader); this.hot.addHookOnce('afterViewRender', () => { this.hot.removeHook('afterGetColHeader', clearColHeader); }); this.hot.batchExecution(() => { if (this.indexesSequenceCache !== null) { this.hot.rowIndexMapper.setIndexesSequence(this.indexesSequenceCache.getValues()); this.hot.rowIndexMapper.unregisterMap(this.pluginKey); this.indexesSequenceCache = null; } }, true); this.hot.columnIndexMapper.unregisterMap(`${this.pluginKey}.columnMeta`); this.columnStatesManager.destroy(); this.columnMetaCache = null; this.columnStatesManager = null; this.unregisterShortcuts(); super.disablePlugin(); } /** * Register shortcuts responsible for toggling column sorting functionality. * * @private */ registerShortcuts() { this.hot.getShortcutManager().getContext('grid').addShortcut({ keys: [['Enter']], callback: () => { const { highlight } = this.hot.getSelectedRangeActive(); this.sort(this.getColumnNextConfig(highlight.col)); // prevent default Enter behavior (move to the next row within a selection range) return false; }, runOnlyIf: () => { var _this$hot$getSelected, _this$hot$getSelected2; const highlight = (_this$hot$getSelected = this.hot.getSelectedRangeActive()) === null || _this$hot$getSelected === void 0 ? void 0 : _this$hot$getSelected.highlight; return highlight && ((_this$hot$getSelected2 = this.hot.getSelectedRangeActive()) === null || _this$hot$getSelected2 === void 0 ? void 0 : _this$hot$getSelected2.isSingle()) && this.hot.selection.isCellVisible(highlight) && highlight.row === -1 && highlight.col >= 0; }, relativeToGroup: _shortcutContexts.EDITOR_EDIT_GROUP, position: 'before', group: SHORTCUTS_GROUP }); } /** * Unregister shortcuts responsible for toggling column sorting functionality. * * @private */ unregisterShortcuts() { this.hot.getShortcutManager().getContext('grid').removeShortcutsByGroup(SHORTCUTS_GROUP); } // DIFF - MultiColumnSorting & ColumnSorting: changed function documentation. /** * Sorts the table by chosen columns and orders. * * @param {undefined|object} sortConfig Single column sort configuration. The configuration object contains `column` and `sortOrder` properties. * First of them contains visual column index, the second one contains sort order (`asc` for ascending, `desc` for descending). * * **Note**: Please keep in mind that every call of `sort` function set an entirely new sort order. Previous sort configs aren't preserved. * * @example * ```js * // sort ascending first visual column * hot.getPlugin('columnSorting').sort({ column: 0, sortOrder: 'asc' }); * ``` * * @fires Hooks#beforeColumnSort * @fires Hooks#afterColumnSort */ sort(sortConfig) { const currentSortConfig = this.getSortConfig(); // We always pass configs defined as an array to `beforeColumnSort` and `afterColumnSort` hooks. const destinationSortConfigs = this.getNormalizedSortConfigs(sortConfig); const sortPossible = this.areValidSortConfigs(destinationSortConfigs); const allowSort = this.hot.runHooks('beforeColumnSort', currentSortConfig, destinationSortConfigs, sortPossible); if (allowSort === false) { return; } if (currentSortConfig.length === 0 && this.indexesSequenceCache === null) { this.indexesSequenceCache = this.hot.rowIndexMapper.registerMap(this.pluginKey, new _translations.IndexesSequence()); this.indexesSequenceCache.setValues(this.hot.rowIndexMapper.getIndexesSequence()); } if (sortPossible) { this.columnStatesManager.setSortStates(destinationSortConfigs); this.sortByPresetSortStates(destinationSortConfigs); this.saveAllSortSettings(destinationSortConfigs); } this.hot.runHooks('afterColumnSort', currentSortConfig, sortPossible ? destinationSortConfigs : currentSortConfig, sortPossible); if (sortPossible) { this.hot.render(); } } /** * Clear the sort performed on the table. */ clearSort() { this.sort([]); } /** * Checks if the table is sorted (any column have to be sorted). * * @returns {boolean} */ isSorted() { return this.enabled && !this.columnStatesManager.isListOfSortedColumnsEmpty(); } /** * Get sort configuration for particular column or for all sorted columns. Objects contain `column` and `sortOrder` properties. * * **Note**: Please keep in mind that returned objects expose **visual** column index under the `column` key. They are handled by the `sort` function. * * @param {number} [column] Visual column index. * @returns {undefined|object|Array} */ getSortConfig(column) { if ((0, _mixed.isDefined)(column)) { return this.columnStatesManager.getColumnSortState(column); } return this.columnStatesManager.getSortStates(); } /** * @description * Warn: Useful mainly for providing server side sort implementation (see in the example below). It doesn't sort the data set. It just sets sort configuration for all sorted columns. * Note: Please keep in mind that this method doesn't re-render the table. * * @example * ```js * beforeColumnSort: function(currentSortConfig, destinationSortConfigs) { * const columnSortPlugin = this.getPlugin('columnSorting'); * * columnSortPlugin.setSortConfig(destinationSortConfigs); * * // const newData = ... // Calculated data set, ie. from an AJAX call. * * this.loadData(newData); // Load new data set and re-render the table. * * return false; // The blockade for the default sort action. * } * ``` * * @param {undefined|object|Array} sortConfig Single column sort configuration or full sort configuration (for all sorted columns). * The configuration object contains `column` and `sortOrder` properties. First of them contains visual column index, the second one contains * sort order (`asc` for ascending, `desc` for descending). */ setSortConfig(sortConfig) { // We always set configs defined as an array. const destinationSortConfigs = this.getNormalizedSortConfigs(sortConfig); if (this.areValidSortConfigs(destinationSortConfigs)) { this.columnStatesManager.setSortStates(destinationSortConfigs); } } /** * Get normalized sort configs. * * @private * @param {object|Array} [sortConfig=[]] Single column sort configuration or full sort configuration (for all sorted columns). * The configuration object contains `column` and `sortOrder` properties. First of them contains visual column index, the second one contains * sort order (`asc` for ascending, `desc` for descending). * @returns {Array} */ getNormalizedSortConfigs() { let sortConfig = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; if (Array.isArray(sortConfig)) { return sortConfig.slice(0, 1); } return [sortConfig]; } /** * Get if sort configs are valid. * * @private * @param {Array} sortConfigs Sort configuration for all sorted columns. Objects contain `column` and `sortOrder` properties. * @returns {boolean} */ areValidSortConfigs(sortConfigs) { const numberOfColumns = this.hot.countCols(); // We don't translate visual indexes to physical indexes. return (0, _utils.areValidSortStates)(sortConfigs) && sortConfigs.every(_ref => { let { column } = _ref; return column <= numberOfColumns && column >= 0; }); } /** * Saves all sorting settings. Saving works only when {@link Options#persistentState} option is enabled. * * @param {Array} sortConfigs Sort configuration for all sorted columns. Objects contain `column` and `sortOrder` properties. * * @private * @fires Hooks#persistentStateSave */ saveAllSortSettings(sortConfigs) { const allSortSettings = this.columnStatesManager.getAllColumnsProperties(); const translateColumnToPhysical = _ref2 => { let { column: visualColumn, ...restOfProperties } = _ref2; return { column: this.hot.toPhysicalColumn(visualColumn), ...restOfProperties }; }; allSortSettings.initialConfig = (0, _array.arrayMap)(sortConfigs, translateColumnToPhysical); this.hot.runHooks('persistentStateSave', 'columnSorting', allSortSettings); } /** * Get all saved sorting settings. Loading works only when {@link Options#persistentState} option is enabled. * * @private * @returns {object} Previously saved sort settings. * * @fires Hooks#persistentStateLoad */ getAllSavedSortSettings() { const storedAllSortSettings = {}; this.hot.runHooks('persistentStateLoad', 'columnSorting', storedAllSortSettings); const allSortSettings = storedAllSortSettings.value; const translateColumnToVisual = _ref3 => { let { column: physicalColumn, ...restOfProperties } = _ref3; return { column: this.hot.toVisualColumn(physicalColumn), ...restOfProperties }; }; if ((0, _mixed.isDefined)(allSortSettings) && Array.isArray(allSortSettings.initialConfig)) { allSortSettings.initialConfig = (0, _array.arrayMap)(allSortSettings.initialConfig, translateColumnToVisual); } return allSortSettings; } /** * Get next sort configuration for particular column. Object contain `column` and `sortOrder` properties. * * **Note**: Please keep in mind that returned object expose **visual** column index under the `column` key. * * @private * @param {number} column Visual column index. * @returns {undefined|object} */ getColumnNextConfig(column) { const sortOrder = this.columnStatesManager.getSortOrderOfColumn(column); if ((0, _mixed.isDefined)(sortOrder)) { const nextSortOrder = (0, _utils.getNextSortOrder)(sortOrder); if ((0, _mixed.isDefined)(nextSortOrder)) { return { column, sortOrder: nextSortOrder }; } return; } const nrOfColumns = this.hot.countCols(); if (Number.isInteger(column) && column >= 0 && column < nrOfColumns) { return { column, sortOrder: (0, _utils.getNextSortOrder)() }; } } /** * Get sort configuration with "next order" for particular column. * * @private * @param {number} columnToChange Visual column index of column which order will be changed. * @param {string} strategyId ID of strategy. Possible values: 'append' and 'replace'. The first one * change order of particular column and change it's position in the sort queue to the last one. The second one * just change order of particular column. * * **Note**: Please keep in mind that returned objects expose **visual** column index under the `column` key. * * @returns {Array} */ getNextSortConfig(columnToChange) { let strategyId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : APPEND_COLUMN_CONFIG_STRATEGY; const indexOfColumnToChange = this.columnStatesManager.getIndexOfColumnInSortQueue(columnToChange); const isColumnSorted = indexOfColumnToChange !== -1; const currentSortConfig = this.getSortConfig(); const nextColumnConfig = this.getColumnNextConfig(columnToChange); if (isColumnSorted) { if ((0, _mixed.isUndefined)(nextColumnConfig)) { return [...currentSortConfig.slice(0, indexOfColumnToChange), ...currentSortConfig.slice(indexOfColumnToChange + 1)]; } if (strategyId === APPEND_COLUMN_CONFIG_STRATEGY) { return [...currentSortConfig.slice(0, indexOfColumnToChange), ...currentSortConfig.slice(indexOfColumnToChange + 1), nextColumnConfig]; } else if (strategyId === REPLACE_COLUMN_CONFIG_STRATEGY) { return [...currentSortConfig.slice(0, indexOfColumnToChange), nextColumnConfig, ...currentSortConfig.slice(indexOfColumnToChange + 1)]; } } if ((0, _mixed.isDefined)(nextColumnConfig)) { return currentSortConfig.concat(nextColumnConfig); } return currentSortConfig; } /** * Get plugin's column config for the specified column index. * * @private * @param {object} columnConfig Configuration inside `columns` property for the specified column index. * @returns {object} */ getPluginColumnConfig(columnConfig) { if ((0, _object.isObject)(columnConfig)) { const pluginColumnConfig = columnConfig[this.pluginKey]; if ((0, _object.isObject)(pluginColumnConfig)) { return pluginColumnConfig; } } return {}; } /** * Get plugin settings related properties, properly merged from cascade settings. * * @private * @param {number} column Visual column index. * @returns {object} */ getMergedPluginSettings(column) { const pluginMainSettings = this.hot.getSettings()[this.pluginKey]; const storedColumnProperties = this.columnStatesManager.getAllColumnsProperties(); const cellMeta = this.hot.getCellMeta(0, column); const columnMeta = Object.getPrototypeOf(cellMeta); if (Array.isArray(columnMeta.columns)) { return Object.assign(storedColumnProperties, pluginMainSettings, this.getPluginColumnConfig(columnMeta.columns[column])); } else if ((0, _function.isFunction)(columnMeta.columns)) { return Object.assign(storedColumnProperties, pluginMainSettings, this.getPluginColumnConfig(columnMeta.columns(column))); } return Object.assign(storedColumnProperties, pluginMainSettings); } /** * Get copy of settings for first cell in the column. * * @private * @param {number} column Visual column index. * @returns {object} */ // TODO: Workaround. Inheriting of non-primitive cell meta values doesn't work. Instead of getting properties from column meta we call this function. // TODO: Remove test named: "should not break the dataset when inserted new row" (#5431). getFirstCellSettings(column) { const cellMeta = this.hot.getCellMeta(0, column); const cellMetaCopy = Object.create(cellMeta); cellMetaCopy[this.pluginKey] = this.columnMetaCache.getValueAtIndex(this.hot.toPhysicalColumn(column)); return cellMetaCopy; } /** * Get number of rows which should be sorted. * * @private * @param {number} numberOfRows Total number of displayed rows. * @returns {number} */ getNumberOfRowsToSort(numberOfRows) { const settings = this.hot.getSettings(); // `maxRows` option doesn't take into account `minSpareRows` option in this case. if (settings.maxRows <= numberOfRows) { return settings.maxRows; } return numberOfRows - settings.minSpareRows; } /** * Performs the sorting using a stable sort function basing on internal state of sorting. * * @param {Array} sortConfigs Sort configuration for all sorted columns. Objects contain `column` and `sortOrder` properties. * @private */ sortByPresetSortStates(sortConfigs) { this.hot.rowIndexMapper.setIndexesSequence(this.indexesSequenceCache.getValues()); if (sortConfigs.length === 0) { return; } const indexesWithData = []; const numberOfRows = this.hot.countRows(); const getDataForSortedColumns = visualRowIndex => (0, _array.arrayMap)(sortConfigs, sortConfig => this.hot.getDataAtCell(visualRowIndex, sortConfig.column)); for (let visualRowIndex = 0; visualRowIndex < this.getNumberOfRowsToSort(numberOfRows); visualRowIndex += 1) { indexesWithData.push([this.hot.toPhysicalRow(visualRowIndex)].concat(getDataForSortedColumns(visualRowIndex))); } const indexesBefore = (0, _array.arrayMap)(indexesWithData, indexWithData => indexWithData[0]); (0, _sortService.sort)(indexesWithData, this.pluginKey, (0, _array.arrayMap)(sortConfigs, sortConfig => sortConfig.sortOrder), (0, _array.arrayMap)(sortConfigs, sortConfig => this.getFirstCellSettings(sortConfig.column))); // Append spareRows for (let visualRowIndex = indexesWithData.length; visualRowIndex < numberOfRows; visualRowIndex += 1) { indexesWithData.push([visualRowIndex].concat(getDataForSortedColumns(visualRowIndex))); } const indexesAfter = (0, _array.arrayMap)(indexesWithData, indexWithData => indexWithData[0]); const indexMapping = new Map((0, _array.arrayMap)(indexesBefore, (indexBefore, indexInsideArray) => [indexBefore, indexesAfter[indexInsideArray]])); const newIndexesSequence = (0, _array.arrayMap)(this.hot.rowIndexMapper.getIndexesSequence(), physicalIndex => { if (indexMapping.has(physicalIndex)) { return indexMapping.get(physicalIndex); } return physicalIndex; }); this.hot.rowIndexMapper.setIndexesSequence(newIndexesSequence); } /** * Sort the table by provided configuration. * * @private * @param {object} allSortSettings All sort config settings. Object may contain `initialConfig`, `indicator`, * `sortEmptyCells`, `headerAction` and `compareFunctionFactory` properties. */ sortBySettings(allSortSettings) { if ((0, _object.isObject)(allSortSettings)) { this.columnStatesManager.updateAllColumnsProperties(allSortSettings); const initialConfig = allSortSettings.initialConfig; if (Array.isArray(initialConfig) || (0, _object.isObject)(initialConfig)) { this.sort(initialConfig); } } else { // Extra render for headers. Their width may change. this.hot.render(); } } /** * Callback for the `onAfterGetColHeader` hook. Adds column sorting CSS classes. * * @param {number} column Visual column index. * @param {Element} TH TH HTML element. */ /** * Update header classes. * * @private * @param {HTMLElement} headerSpanElement Header span element. * @param {...*} args Extra arguments for helpers. */ updateHeaderClasses(headerSpanElement) { (0, _element.removeClass)(headerSpanElement, (0, _domHelpers.getClassesToRemove)(headerSpanElement)); if (this.enabled !== false) { for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { args[_key3 - 1] = arguments[_key3]; } (0, _element.addClass)(headerSpanElement, (0, _domHelpers.getClassesToAdd)(...args)); } } /** * Overwriting base plugin's `onUpdateSettings` method. Please keep in mind that `onAfterUpdateSettings` isn't called * for `updateSettings` in specific situations. * * @private * @param {object} newSettings New settings object. */ onUpdateSettings(newSettings) { super.onUpdateSettings(newSettings); if (this.columnMetaCache !== null) { // Column meta cache base on settings, thus we should re-init the map. this.columnMetaCache.init(this.hot.columnIndexMapper.getNumberOfIndexes()); } if ((0, _mixed.isDefined)(newSettings[this.pluginKey])) { this.sortBySettings(newSettings[this.pluginKey]); } } /** * Callback for the `afterLoadData` hook. * * @param {boolean} initialLoad Flag that determines whether the data has been loaded during the initialization. */ /** * Indicates if clickable header was clicked. * * @private * @param {MouseEvent} event The `mousedown` event. * @param {number} column Visual column index. * @returns {boolean} */ wasClickableHeaderClicked(event, column) { const pluginSettingsForColumn = this.getFirstCellSettings(column)[this.pluginKey]; const headerActionEnabled = pluginSettingsForColumn.headerAction; return headerActionEnabled && (0, _element.hasClass)(event.target, _utils.HEADER_SPAN_CLASS); } /** * Changes the behavior of selection / dragging. * * @param {MouseEvent} event The `mousedown` event. * @param {CellCoords} coords Visual coordinates. * @param {HTMLElement} TD The cell element. * @param {object} controller An object with properties `row`, `column` and `cell`. Each property contains * a boolean value that allows or disallows changing the selection for that particular area. */ /** * Callback for the `onAfterOnCellMouseDown` hook. * * @private * @param {Event} event Event which are provided by hook. * @param {CellCoords} coords Visual coords of the selected cell. */ onAfterOnCellMouseDown(event, coords) { if ((0, _utils.wasHeaderClickedProperly)(coords.row, coords.col, event) === false) { return; } if (this.wasClickableHeaderClicked(event, coords.col)) { if (this.hot.getShortcutManager().isCtrlPressed()) { this.hot.deselectCell(); this.hot.selectColumns(coords.col); } const activeEditor = this.hot.getActiveEditor(); const nextConfig = this.getColumnNextConfig(coords.col); if (activeEditor !== null && activeEditor !== void 0 && activeEditor.isOpened() && this.hot.getCellValidator(activeEditor.row, activeEditor.col)) { // Postpone sorting until the cell's value is validated and saved. this.hot.addHookOnce('postAfterValidate', () => { this.sort(nextConfig); }); } else { this.sort(nextConfig); } } } /** * Destroys the plugin instance. */ destroy() { var _this$columnStatesMan; // TODO: Probably not supported yet by ESLint: https://github.com/eslint/eslint/issues/11045 // eslint-disable-next-line no-unused-expressions (_this$columnStatesMan = this.columnStatesManager) === null || _this$columnStatesMan === void 0 || _this$columnStatesMan.destroy(); super.destroy(); } } exports.ColumnSorting = ColumnSorting; function _loadOrSortBySettings() { const storedAllSortSettings = this.getAllSavedSortSettings(); if ((0, _object.isObject)(storedAllSortSettings)) { this.sortBySettings(storedAllSortSettings); } else { const allSortSettings = this.hot.getSettings()[this.pluginKey]; this.sortBySettings(allSortSettings); } } function _onAfterGetColHeader(column, TH) { const headerSpanElement = (0, _utils.getHeaderSpanElement)(TH); if ((0, _utils.isFirstLevelColumnHeader)(column, TH) === false || headerSpanElement === null) { return; } const pluginSettingsForColumn = this.getFirstCellSettings(column)[this.pluginKey]; const showSortIndicator = pluginSettingsForColumn.indicator; const headerActionEnabled = pluginSettingsForColumn.headerAction; this.updateHeaderClasses(headerSpanElement, this.columnStatesManager, column, showSortIndicator, headerActionEnabled); if (this.hot.getSettings().ariaTags) { const currentSortState = this.columnStatesManager.getSortOrderOfColumn(column); (0, _element.setAttribute)(TH, ...(0, _a11y.A11Y_SORT)(currentSortState ? `${currentSortState}ending` : 'none')); } } function _onAfterLoadData(initialLoad) { if (initialLoad === true) { // TODO: Workaround? It should be refactored / described. if (this.hot.view) { _assertClassBrand(_ColumnSorting_brand, this, _loadOrSortBySettings).call(this); } } } function _onBeforeOnCellMouseDown(event, coords, TD, controller) { if ((0, _utils.wasHeaderClickedProperly)(coords.row, coords.col, event) === false) { return; } if (this.wasClickableHeaderClicked(event, coords.col) && this.hot.getShortcutManager().isCtrlPressed()) { controller.column = true; } }