<commit_before>
import * as dom from './../../dom.js';
import {eventManager as eventManagerObject} from './../../eventManager.js';
import {registerPlugin} from './../../plugins.js';

export {ColumnSorting};

//registerPlugin('columnSorting', ColumnSorting);

/**
 * This plugin sorts the view by a column (but does not sort the data source!)
 *
 * @private
 * @class ColumnSorting
 * @plugin
 * @constructor
 */
function ColumnSorting() {
  var plugin = this;

  this.init = function(source) {
    var instance = this;
    var sortingSettings = instance.getSettings().columnSorting;
    var sortingColumn, sortingOrder;

    instance.sortingEnabled = !! (sortingSettings);

    if (instance.sortingEnabled) {
      instance.sortIndex = [];

      var loadedSortingState = loadSortingState.call(instance);

      if (typeof loadedSortingState != 'undefined') {
        sortingColumn = loadedSortingState.sortColumn;
        sortingOrder = loadedSortingState.sortOrder;
      } else {
        sortingColumn = sortingSettings.column;
        sortingOrder = sortingSettings.sortOrder;
      }
      plugin.sortByColumn.call(instance, sortingColumn, sortingOrder);

      instance.sort = function() {
        var args = Array.prototype.slice.call(arguments);

        return plugin.sortByColumn.apply(instance, args);
      };

      if (typeof instance.getSettings().observeChanges == 'undefined') {
        enableObserveChangesPlugin.call(instance);
      }

      if (source == 'afterInit') {
        bindColumnSortingAfterClick.call(instance);

        instance.addHook('afterCreateRow', plugin.afterCreateRow);
        instance.addHook('afterRemoveRow', plugin.afterRemoveRow);
        instance.addHook('afterLoadData', plugin.init);
      }
    } else {
      delete instance.sort;

      instance.removeHook('afterCreateRow', plugin.afterCreateRow);
      instance.removeHook('afterRemoveRow', plugin.afterRemoveRow);
      instance.removeHook('afterLoadData', plugin.init);
    }
  };

  this.setSortingColumn = function(col, order) {
    var instance = this;

    if (typeof col == 'undefined') {
      delete instance.sortColumn;
      delete instance.sortOrder;

      return;
    } else if (instance.sortColumn === col && typeof order == 'undefined') {
      instance.sortOrder = !instance.sortOrder;
    } else {
      instance.sortOrder = typeof order != 'undefined' ? order : true;
    }

    instance.sortColumn = col;

  };

  this.sortByColumn = function(col, order) {
    var instance = this;

    plugin.setSortingColumn.call(instance, col, order);

    if (typeof instance.sortColumn == 'undefined') {
      return;
    }

    Handsontable.hooks.run(instance, 'beforeColumnSort', instance.sortColumn, instance.sortOrder);

    plugin.sort.call(instance);
    instance.render();

    saveSortingState.call(instance);

    Handsontable.hooks.run(instance, 'afterColumnSort', instance.sortColumn, instance.sortOrder);
  };

  var saveSortingState = function() {
    var instance = this;

    var sortingState = {};

    if (typeof instance.sortColumn != 'undefined') {
      sortingState.sortColumn = instance.sortColumn;
    }

    if (typeof instance.sortOrder != 'undefined') {
      sortingState.sortOrder = instance.sortOrder;
    }

    if (sortingState.hasOwnProperty('sortColumn') || sortingState.hasOwnProperty('sortOrder')) {
      Handsontable.hooks.run(instance, 'persistentStateSave', 'columnSorting', sortingState);
    }

  };

  var loadSortingState = function() {
    var instance = this;
    var storedState = {};
    Handsontable.hooks.run(instance, 'persistentStateLoad', 'columnSorting', storedState);

    return storedState.value;
  };

  var bindColumnSortingAfterClick = function() {
    var instance = this;

    var eventManager = eventManagerObject(instance);

    eventManager.addEventListener(instance.rootElement, 'click', function(e) {
      if (dom.hasClass(e.target, 'columnSorting')) {
        var col = getColumn(e.target);
        plugin.sortByColumn.call(instance, col);
      }
    });

    function countRowHeaders() {
      var THs = instance.view.TBODY.querySelector('tr').querySelectorAll('th');
      return THs.length;
    }

    function getColumn(target) {
      var TH = dom.closest(target, 'TH');
      return dom.index(TH) - countRowHeaders();
    }
  };

  function enableObserveChangesPlugin() {
    var instance = this;
    instance._registerTimeout(setTimeout(function() {
      instance.updateSettings({
        observeChanges: true
      });
    }, 0));
  }

  function defaultSort(sortOrder) {
    return function(a, b) {
      if (typeof a[1] == "string") {
        a[1] = a[1].toLowerCase();
      }
      if (typeof b[1] == "string") {
        b[1] = b[1].toLowerCase();
      }

      if (a[1] === b[1]) {
        return 0;
      }
      if (a[1] === null || a[1] === "") {
        return 1;
      }
      if (b[1] === null || b[1] === "") {
        return -1;
      }
      if (a[1] < b[1]) {
        return sortOrder ? -1 : 1;
      }
      if (a[1] > b[1]) {
        return sortOrder ? 1 : -1;
      }
      return 0;
    };
  }

  function dateSort(sortOrder) {
    return function(a, b) {
      if (a[1] === b[1]) {
        return 0;
      }
      if (a[1] === null) {
        return 1;
      }
      if (b[1] === null) {
        return -1;
      }

      var aDate = new Date(a[1]);
      var bDate = new Date(b[1]);

      if (aDate < bDate) {
        return sortOrder ? -1 : 1;
      }
      if (aDate > bDate) {
        return sortOrder ? 1 : -1;
      }

      return 0;
    };
  }

  this.sort = function() {
    var instance = this;

    if (typeof instance.sortOrder == 'undefined') {
      return;
    }

    instance.sortingEnabled = false; //this is required by translateRow plugin hook
    instance.sortIndex.length = 0;

    var colOffset = this.colOffset();
    for (var i = 0, ilen = this.countRows() - instance.getSettings()['minSpareRows']; i < ilen; i++) {
      this.sortIndex.push([i, instance.getDataAtCell(i, this.sortColumn + colOffset)]);
    }

    var colMeta = instance.getCellMeta(0, instance.sortColumn);
    var sortFunction;
    switch (colMeta.type) {
      case 'date':
        sortFunction = dateSort;
        break;
      default:
        sortFunction = defaultSort;
    }

    this.sortIndex.sort(sortFunction(instance.sortOrder));

    //Append spareRows
    for (var i = this.sortIndex.length; i < instance.countRows(); i++) {
      this.sortIndex.push([i, instance.getDataAtCell(i, this.sortColumn + colOffset)]);
    }

    instance.sortingEnabled = true; //this is required by translateRow plugin hook
  };

  this.translateRow = function(row) {
    var instance = this;

    if (instance.sortingEnabled && instance.sortIndex && instance.sortIndex.length && instance.sortIndex[row]) {
      return instance.sortIndex[row][0];
    }

    return row;
  };

  this.untranslateRow = function(row) {
    var instance = this;
    if (instance.sortingEnabled && instance.sortIndex && instance.sortIndex.length) {
      for (var i = 0; i < instance.sortIndex.length; i++) {
        if (instance.sortIndex[i][0] == row) {
          return i;
        }
      }
    }
  };

  this.getColHeader = function(col, TH) {
    if (this.getSettings().columnSorting && col >= 0) {
      dom.addClass(TH.querySelector('.colHeader'), 'columnSorting');
    }
  };

  function isSorted(instance) {
    return typeof instance.sortColumn != 'undefined';
  }

  this.afterCreateRow = function(index, amount) {
    var instance = this;

    if (!isSorted(instance)) {
      return;
    }


    for (var i = 0; i < instance.sortIndex.length; i++) {
      if (instance.sortIndex[i][0] >= index) {
        instance.sortIndex[i][0] += amount;
      }
    }

    for (var i = 0; i < amount; i++) {
      instance.sortIndex.splice(index + i, 0, [index + i, instance.getData()[index + i][instance.sortColumn + instance.colOffset()]]);
    }



    saveSortingState.call(instance);

  };

  this.afterRemoveRow = function(index, amount) {
    var instance = this;

    if (!isSorted(instance)) {
      return;
    }

    var physicalRemovedIndex = plugin.translateRow.call(instance, index);

    instance.sortIndex.splice(index, amount);

    for (var i = 0; i < instance.sortIndex.length; i++) {

      if (instance.sortIndex[i][0] > physicalRemovedIndex) {
        instance.sortIndex[i][0] -= amount;
      }
    }

    saveSortingState.call(instance);

  };

  this.afterChangeSort = function(changes /*, source*/ ) {
    var instance = this;
    var sortColumnChanged = false;
    var selection = {};
    if (!changes) {
      return;
    }

    for (var i = 0; i < changes.length; i++) {
      if (changes[i][1] == instance.sortColumn) {
        sortColumnChanged = true;
        selection.row = plugin.translateRow.call(instance, changes[i][0]);
        selection.col = changes[i][1];
        break;
      }
    }

    if (sortColumnChanged) {
      instance._registerTimeout(setTimeout(function() {
        plugin.sort.call(instance);
        instance.render();
        instance.selectCell(plugin.untranslateRow.call(instance, selection.row), selection.col);
      }, 0));
    }
  };
}
var htSortColumn = new ColumnSorting();

Handsontable.hooks.add('afterInit', function () {
  htSortColumn.init.call(this, 'afterInit');
});
Handsontable.hooks.add('afterUpdateSettings', function () {
  htSortColumn.init.call(this, 'afterUpdateSettings');
});
Handsontable.hooks.add('modifyRow', htSortColumn.translateRow);
Handsontable.hooks.add('afterGetColHeader', htSortColumn.getColHeader);

Handsontable.hooks.register('beforeColumnSort');
Handsontable.hooks.register('afterColumnSort');<commit_msg>Rewrite column sorting to ES6 #2396<commit_after>import * as dom from './../../dom.js';
import {eventManager as eventManagerObject} from './../../eventManager.js';
import BasePlugin from './../_base.js';
import {registerPlugin} from './../../plugins.js';

//registerPlugin('columnSorting', ColumnSorting);

/**
 * This plugin sorts the view by a column (but does not sort the data source!)
 *
 * @private
 * @class ColumnSorting
 * @plugin
 * @constructor
 */
class ColumnSorting extends BasePlugin {
  /**
   * @param {Object} hotInstance
   */
  constructor(hotInstance) {
    super(hotInstance);
    let _this = this;
    //this.hot.addHook('afterContextMenuShow', htContextMenu => this.setupZeroClipboard(htContextMenu));

    this.hot.addHook('afterInit', () => this.init.call(this, 'afterInit'));
    this.hot.addHook('afterUpdateSettings', () => this.init.call(this, 'afterUpdateSettings'));
    this.hot.addHook('modifyRow', function() {
      return _this.translateRow.apply(_this, arguments);
    });
    this.hot.addHook('afterGetColHeader', function() {
      return _this.getColHeader.apply(_this, arguments);
    });

    Handsontable.hooks.register('beforeColumnSort');
    Handsontable.hooks.register('afterColumnSort');

    //Handsontable.hooks.add('afterInit', function () {
    //  htSortColumn.init.call(this, 'afterInit');
    //});
    //Handsontable.hooks.add('afterUpdateSettings', function () {
    //  htSortColumn.init.call(this, 'afterUpdateSettings');
    //});
    //Handsontable.hooks.add('modifyRow', htSortColumn.translateRow);
    //Handsontable.hooks.add('afterGetColHeader', htSortColumn.getColHeader);


  }

  init(source) {
    let sortingSettings = this.hot.getSettings().columnSorting,
      _this = this;

    this.hot.sortingEnabled = !!(sortingSettings);

    if (this.hot.sortingEnabled) {
      this.hot.sortIndex = [];

      let loadedSortingState = this.loadSortingState(),
        sortingColumn,
        sortingOrder;

      if (typeof loadedSortingState != 'undefined') {
        sortingColumn = loadedSortingState.sortColumn;
        sortingOrder = loadedSortingState.sortOrder;

      } else {
        sortingColumn = sortingSettings.column;
        sortingOrder = sortingSettings.sortOrder;
      }

      this.sortByColumn(sortingColumn, sortingOrder);

      this.hot.sort = function() {
        let args = Array.prototype.slice.call(arguments);

        return _this.sortByColumn.apply(_this, args);
      };

      if (typeof this.hot.getSettings().observeChanges == 'undefined') {
        this.enableObserveChangesPlugin();
      }

      if (source == 'afterInit') {
        this.bindColumnSortingAfterClick();

        this.hot.addHook('afterCreateRow', function() {
          _this.afterCreateRow.apply(_this, arguments);
        });
        this.hot.addHook('afterRemoveRow', function() {
          _this.afterRemoveRow.apply(_this, arguments);
        });
        this.hot.addHook('afterLoadData', function() {
          _this.init.apply(_this, arguments);
        });
      }
    } else {
      this.hot.sort = void 0;

      this.hot.removeHook('afterCreateRow', this.afterCreateRow);
      this.hot.removeHook('afterRemoveRow', this.afterRemoveRow);
      this.hot.removeHook('afterLoadData', this.init);
    }
  }

  setSortingColumn(col, order) {
    if (typeof col == 'undefined') {
      this.hot.sortColumn = void 0;
      this.hot.sortOrder = void 0;

      return;
    } else if (this.hot.sortColumn === col && typeof order == 'undefined') {
      this.hot.sortOrder = !this.hot.sortOrder;
    } else {
      this.hot.sortOrder = typeof order != 'undefined' ? order : true;
    }

    this.hot.sortColumn = col;
  }

  sortByColumn(col, order) {
    this.setSortingColumn(col, order);

    if (typeof this.hot.sortColumn == 'undefined') {
      return;
    }

    Handsontable.hooks.run(this.hot, 'beforeColumnSort', this.hot.sortColumn, this.hot.sortOrder);

    this.sort();
    this.hot.render();

    this.saveSortingState();

    Handsontable.hooks.run(this.hot, 'afterColumnSort', this.hot.sortColumn, this.hot.sortOrder);
  }

  saveSortingState() {
    let sortingState = {};

    if (typeof this.hot.sortColumn != 'undefined') {
      sortingState.sortColumn = this.hot.sortColumn;
    }

    if (typeof this.hot.sortOrder != 'undefined') {
      sortingState.sortOrder = this.hot.sortOrder;
    }

    if (sortingState.hasOwnProperty('sortColumn') || sortingState.hasOwnProperty('sortOrder')) {
      Handsontable.hooks.run(this.hot, 'persistentStateSave', 'columnSorting', sortingState);
    }

  }

  loadSortingState() {
    let storedState = {};
    Handsontable.hooks.run(this.hot, 'persistentStateLoad', 'columnSorting', storedState);

    return storedState.value;
  }

  bindColumnSortingAfterClick() {
    let eventManager = eventManagerObject(this.hot),
      _this = this;

    eventManager.addEventListener(this.hot.rootElement, 'click', function(e) {
      if (dom.hasClass(e.target, 'columnSorting')) {
        let col = getColumn(e.target);
        _this.sortByColumn(col);
      }
    });

    function countRowHeaders() {
      let THs = _this.hot.view.TBODY.querySelector('tr').querySelectorAll('th');
      return THs.length;
    }

    function getColumn(target) {
      let TH = dom.closest(target, 'TH');
      return dom.index(TH) - countRowHeaders();
    }
  }

  enableObserveChangesPlugin() {
    let _this = this;

    this.hot._registerTimeout(
      setTimeout(function() {
        _this.hot.updateSettings({
          observeChanges: true
        });
      }, 0));
  }

  defaultSort(sortOrder) {
    return function(a, b) {
      if (typeof a[1] == "string") {
        a[1] = a[1].toLowerCase();
      }
      if (typeof b[1] == "string") {
        b[1] = b[1].toLowerCase();
      }

      if (a[1] === b[1]) {
        return 0;
      }
      if (a[1] === null || a[1] === "") {
        return 1;
      }
      if (b[1] === null || b[1] === "") {
        return -1;
      }
      if (a[1] < b[1]) {
        return sortOrder ? -1 : 1;
      }
      if (a[1] > b[1]) {
        return sortOrder ? 1 : -1;
      }
      return 0;
    };
  }

  dateSort(sortOrder) {
    return function(a, b) {
      if (a[1] === b[1]) {
        return 0;
      }
      if (a[1] === null) {
        return 1;
      }
      if (b[1] === null) {
        return -1;
      }

      var aDate = new Date(a[1]);
      var bDate = new Date(b[1]);

      if (aDate < bDate) {
        return sortOrder ? -1 : 1;
      }
      if (aDate > bDate) {
        return sortOrder ? 1 : -1;
      }

      return 0;
    };
  }

  sort() {
    if (typeof this.hot.sortOrder == 'undefined') {
      return;
    }

    let colMeta,
      sortFunction;

    this.hot.sortingEnabled = false; //this is required by translateRow plugin hook
    this.hot.sortIndex.length = 0;

    var colOffset = this.hot.colOffset();
    for (var i = 0, ilen = this.hot.countRows() - this.hot.getSettings()['minSpareRows']; i < ilen; i++) {
      this.hot.sortIndex.push([i, this.hot.getDataAtCell(i, this.hot.sortColumn + colOffset)]);
    }

    colMeta = this.hot.getCellMeta(0, this.hot.sortColumn);

    switch (colMeta.type) {
      case 'date':
        sortFunction = this.dateSort;
        break;
      default:
        sortFunction = this.defaultSort;
    }

    this.hot.sortIndex.sort(sortFunction(this.hot.sortOrder));

    //Append spareRows
    for (var i = this.hot.sortIndex.length; i < this.hot.countRows(); i++) {
      this.hot.sortIndex.push([i, this.hot.getDataAtCell(i, this.hot.sortColumn + colOffset)]);
    }

    this.hot.sortingEnabled = true; //this is required by translateRow plugin hook
  }

  translateRow(row) {
    if (this.hot.sortingEnabled && this.hot.sortIndex && this.hot.sortIndex.length && this.hot.sortIndex[row]) {
      return this.hot.sortIndex[row][0];
    }

    return row;
  }

  untranslateRow(row) {
    if (this.hot.sortingEnabled && this.hot.sortIndex && this.hot.sortIndex.length) {
      for (var i = 0; i < this.hot.sortIndex.length; i++) {
        if (this.hot.sortIndex[i][0] == row) {
          return i;
        }
      }
    }
  }

  getColHeader(col, TH) {
    if (this.hot.getSettings().columnSorting && col >= 0) {
      dom.addClass(TH.querySelector('.colHeader'), 'columnSorting');
    }
  }

  isSorted() {
    return typeof this.hot.sortColumn != 'undefined';
  }

  afterCreateRow(index, amount) {
    if (!this.isSorted()) {
      return;
    }

    for (var i = 0; i < this.hot.sortIndex.length; i++) {
      if (this.hot.sortIndex[i][0] >= index) {
        this.hot.sortIndex[i][0] += amount;
      }
    }

    for (var i = 0; i < amount; i++) {
      this.hot.sortIndex.splice(index + i, 0, [index + i, this.hot.getData()[index + i][this.hot.sortColumn + this.hot.colOffset()]]);
    }

    this.saveSortingState();
  }

  afterRemoveRow(index, amount) {
    if (!this.isSorted()) {
      return;
    }

    let physicalRemovedIndex = this.translateRow(index);

    this.hot.sortIndex.splice(index, amount);

    for (var i = 0; i < this.hot.sortIndex.length; i++) {
      if (this.hot.sortIndex[i][0] > physicalRemovedIndex) {
        this.hot.sortIndex[i][0] -= amount;
      }
    }

    this.saveSortingState();
  }

  afterChangeSort(changes /*, source*/) {
    let sortColumnChanged = false,
      selection = {},
      _this = this;

    if (!changes) {
      return;
    }

    for (var i = 0; i < changes.length; i++) {
      if (changes[i][1] == this.hot.sortColumn) {
        sortColumnChanged = true;
        selection.row = this.translateRow(changes[i][0]);
        selection.col = changes[i][1];
        break;
      }
    }

    if (sortColumnChanged) {
      this.hot._registerTimeout(setTimeout(function() {
        _this.sort();
        _this.hot.render();
        _this.hot.selectCell(this.untranslateRow(selection.row), selection.col);
      }, 0));
    }
  }

}

export default ColumnSorting;

registerPlugin('columnSorting', ColumnSorting);
{'fraction_non_alphanumeric': 0.14756264931632188, 'fraction_numerical': 0.006404717124993646, 'mean_word_length': 2.6835798539599325, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6975755', 'n_tokens_mistral': 6342, 'n_tokens_neox': 6165, 'n_words': 1188}