"use strict";

exports.__esModule = true;
require("core-js/modules/es.error.cause.js");
var _columnSorting = require("../columnSorting");
var _sortService = require("../columnSorting/sortService");
var _utils = require("../columnSorting/utils");
var _element = require("../../helpers/dom/element");
var _rootComparator = require("./rootComparator");
var _utils2 = require("./utils");
var _domHelpers = require("./domHelpers");
var _a11y = require("../../helpers/a11y");
var _constants = require("../../i18n/constants");
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
const PLUGIN_KEY = 'multiColumnSorting';
exports.PLUGIN_KEY = PLUGIN_KEY;
const PLUGIN_PRIORITY = 170;
exports.PLUGIN_PRIORITY = PLUGIN_PRIORITY;
const CONFLICTED_PLUGIN_KEY = 'columnSorting';
const SHORTCUTS_GROUP = PLUGIN_KEY;
(0, _sortService.registerRootComparator)(PLUGIN_KEY, _rootComparator.rootComparator);

/**
 * @plugin MultiColumnSorting
 * @class MultiColumnSorting
 *
 * @description
 * This plugin sorts the view by columns (but does not sort the data source!). To enable the plugin, set the
 * {@link Options#multiColumnSorting} property to the correct value (see the examples below).
 *
 * @example
 * ```js
 * // as boolean
 * multiColumnSorting: true
 *
 * // as an object with initial sort config (sort ascending for column at index 1 and then sort descending for column at index 0)
 * multiColumnSorting: {
 *   initialConfig: [{
 *     column: 1,
 *     sortOrder: 'asc'
 *   }, {
 *     column: 0,
 *     sortOrder: 'desc'
 *   }]
 * }
 *
 * // as an object which define specific sorting options for all columns
 * multiColumnSorting: {
 *   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: {@link Options#columns}
 * columns: [{
 *   multiColumnSorting: {
 *     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)
 *       }
 *     }
 *   }
 * }]
 * ```
 */
class MultiColumnSorting extends _columnSorting.ColumnSorting {
  constructor() {
    super(...arguments);
    /**
     * Main settings key designed for the plugin.
     *
     * @private
     * @type {string}
     */
    _defineProperty(this, "pluginKey", PLUGIN_KEY);
  }
  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 MultiColumnSorting#enablePlugin} method is called.
   *
   * @returns {boolean}
   */
  isEnabled() {
    return super.isEnabled();
  }

  /**
   * Enables the plugin functionality for this Handsontable instance.
   */
  enablePlugin() {
    if (!this.enabled && this.hot.getSettings()[this.pluginKey] && this.hot.getSettings()[CONFLICTED_PLUGIN_KEY]) {
      (0, _utils2.warnAboutPluginsConflict)();
    }
    super.enablePlugin();
  }

  /**
   * Disables the plugin functionality for this Handsontable instance.
   */
  disablePlugin() {
    super.disablePlugin();
  }

  /**
   * Register shortcuts responsible for toggling column sorting functionality.
   *
   * @private
   */
  registerShortcuts() {
    super.registerShortcuts();
    this.hot.getShortcutManager().getContext('grid').addShortcut({
      keys: [['Shift', 'Enter']],
      callback: () => {
        const {
          highlight
        } = this.hot.getSelectedRangeLast();
        if (highlight.row === -1 && highlight.col >= 0) {
          this.sort(this.getNextSortConfig(highlight.col, _columnSorting.APPEND_COLUMN_CONFIG_STRATEGY));
        }
      },
      runOnlyIf: () => {
        var _this$hot$getSelected;
        const highlight = (_this$hot$getSelected = this.hot.getSelectedRangeLast()) === null || _this$hot$getSelected === void 0 ? void 0 : _this$hot$getSelected.highlight;
        return highlight && this.hot.selection.isCellVisible(highlight) && highlight.isHeader();
      },
      group: SHORTCUTS_GROUP
    });
  }

  /**
   * Unregister shortcuts responsible for toggling column sorting functionality.
   *
   * @private
   */
  unregisterShortcuts() {
    super.unregisterShortcuts();
    this.hot.getShortcutManager().getContext('grid').removeShortcutsByGroup(SHORTCUTS_GROUP);
  }

  /**
   * Sorts the table by chosen columns and orders.
   *
   * @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).
   *
   * **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('multiColumnSorting').sort({ column: 0, sortOrder: 'asc' });
   *
   * // sort first two visual column in the defined sequence
   * hot.getPlugin('multiColumnSorting').sort([{
   *   column: 1, sortOrder: 'asc'
   * }, {
   *   column: 0, sortOrder: 'desc'
   * }]);
   * ```
   *
   * @fires Hooks#beforeColumnSort
   * @fires Hooks#afterColumnSort
   */
  sort(sortConfig) {
    super.sort(sortConfig);
  }

  /**
   * Clear the sort performed on the table.
   */
  clearSort() {
    super.clearSort();
  }

  /**
   * Checks if the table is sorted (any column have to be sorted).
   *
   * @returns {boolean}
   */
  isSorted() {
    return super.isSorted();
  }

  /**
   * 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) {
    return super.getSortConfig(column);
  }

  /**
   * @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('multiColumnSorting');
   *
   *   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) {
    super.setSortConfig(sortConfig);
  }

  /**
   * 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;
    }
    return [sortConfig];
  }

  /**
   * Update header classes.
   *
   * @private
   * @param {HTMLElement} headerSpanElement Header span element.
   * @param {...*} args Extra arguments for helpers.
   */
  updateHeaderClasses(headerSpanElement) {
    for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
      args[_key - 1] = arguments[_key];
    }
    super.updateHeaderClasses(headerSpanElement, ...args);
    (0, _element.removeClass)(headerSpanElement, (0, _domHelpers.getClassesToRemove)(headerSpanElement));
    if (this.enabled !== false) {
      (0, _element.addClass)(headerSpanElement, (0, _domHelpers.getClassesToAdd)(...args));
    }
  }

  /**
   * Update sorting indicator.
   *
   * @private
   * @param {number} column Visual column index.
   * @param {HTMLElement} headerSpanElement Header span element.
   */
  updateSortingIndicator(column, headerSpanElement) {
    super.updateSortingIndicator(column, headerSpanElement);
    const indicatorElement = headerSpanElement.querySelector('.columnSortingIndicator');
    if (!indicatorElement || !this.hot.getSettings().ariaTags || !this.columnStatesManager.isColumnSorted(column) || this.columnStatesManager.getNumberOfSortedColumns() <= 1) {
      return;
    }
    const multiColumnSortingOrder = this.columnStatesManager.getIndexOfColumnInSortQueue(column) + 1;
    const a11yLabelAttribute = (0, _a11y.A11Y_LABEL)(`${this.hot.getTranslatedPhrase(_constants.COLUMN_HEADER_LABEL_MULTI_COLUMN_SORT_ORDER)} ${multiColumnSortingOrder}.`);
    (0, _element.removeAttribute)(indicatorElement, (0, _a11y.A11Y_HIDDEN)()[0]);
    (0, _element.setAttribute)(indicatorElement, ...a11yLabelAttribute);
  }

  /**
   * 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) {
    if (this.hot.getSettings()[this.pluginKey] && this.hot.getSettings()[CONFLICTED_PLUGIN_KEY]) {
      (0, _utils2.warnAboutPluginsConflict)();
    }
    super.onUpdateSettings(newSettings);
  }

  /**
   * 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);
        this.sort(this.getNextSortConfig(coords.col, _columnSorting.APPEND_COLUMN_CONFIG_STRATEGY));
      } else {
        this.sort(this.getColumnNextConfig(coords.col));
      }
    }
  }
}
exports.MultiColumnSorting = MultiColumnSorting;