APIs

Show:
/**
  @module ember-flexberry
*/

import Mixin from '@ember/object/mixin';
import { computed } from '@ember/object';
import { inject as service} from '@ember/service';
import serializeSortingParam from '../utils/serialize-sorting-param';

/**
  Mixin for {{#crossLink "DS.Controller"}}Controller{{/crossLink}} to support
  sorting on {{#crossLink "ObjectListView"}}{{/crossLink}}.

  @example
    ```javascript
    // app/controllers/employees.js
    import Controller from '@ember/controller';
    import SortableController from 'ember-flexberry/mixins/sortable-controller'
    export default Controller.extend(SortableController, {
    });
    ```
    ```javascript
    // app/routes/employees.js
    import Route from '@ember/routing/route';
    import SortableRoute from 'ember-flexberry/mixins/sortable-route'
    export default Route.extend(SortableRoute, {
    });
    ```
    ```handlebars
    <!-- app/templates/employees.hbs -->
    ...
    {{flexberry-objectlistview
      ...
      orderable=true
      sortByColumn=(action 'sortByColumn')
      addColumnToSorting=(action 'addColumnToSorting')
      ...
    }}
    ...
    ```

  @class SortableControllerMixin
  @uses <a href="https://www.emberjs.com/api/ember/release/classes/Mixin">Mixin</a>
  @public
 */
export default Mixin.create({
  /**
    Defines which query parameters the controller accepts.
    [More info](https://emberjs.com/api/ember/release/classes/Controller#property_queryParams).

    @property queryParams
    @type Array
    @default ['sort']
  */
  queryParams: ['sort'],

  /**
    Default value for sorting.

    @property sortDefaultValue
    @type String
  */
  sortDefaultValue: null,

  /**
    String with sorting parameters.

    @property sort
    @type String
  */
  sort: null,

  _userSettingsService: service('user-settings'),

  /**
    Dictionary with sorting data related to properties.

    @property computedSorting
    @type Object
    @readOnly
  */
  computedSorting: computed('model.sorting', function() {
    let sorting = this.get('model.sorting');
    let result = {};

    if (sorting) {
      for (let i = 0; i < sorting.length; i++) {
        let propName = sorting[i].propName;
        let sortDef = {
          sortAscending: sorting[i].direction === 'asc',
          sortNumber: i + 1
        };
        result[propName] = sortDef;
      }
    }

    return result;
  }),

  actions: {
    /**
      Sorting list by column.

      @method actions.sortByColumn
      @param {Object} column Column for sorting.
      @param {String} sortPath Path to oldSorting.
    */
    sortByColumn: function(column, componentName, sortPath = 'model.sorting') {
      let propName = column.propName;
      let oldSorting = this.get(sortPath);
      let newSorting = [];
      let sortDirection;
      if (oldSorting) {
        sortDirection = 'asc';
        for (let i = 0; i < oldSorting.length; i++) {
          if (oldSorting[i].propName === propName) {
            sortDirection = this._getNextSortDirection(oldSorting[i].direction);
            break;
          }
        }
      } else {
        sortDirection = 'asc';
      }

      newSorting.push({ propName: propName, direction: sortDirection });

      let sortQueryParam = serializeSortingParam(newSorting, this.get('sortDefaultValue'));
      this.set('sort', sortQueryParam);
    },

    /**
      Add column into end list sorting.

      @method actions.addColumnToSorting
      @param {Object} column Column for sorting.
      @param {String} sortPath Path to oldSorting.
    */
    addColumnToSorting: function(column, componentName, sortPath = 'model.sorting') {
      let propName = column.propName;
      let oldSorting = this.get(sortPath);
      let newSorting = [];
      let changed = false;

      for (let i = 0; i < oldSorting.length; i++) {
        if (oldSorting[i].propName === propName) {
          let newDirection = this._getNextSortDirection(oldSorting[i].direction);
          newSorting.push({ propName: propName, direction: newDirection });
          changed = true;
        } else {
          newSorting.push(oldSorting[i]);
        }
      }

      if (!changed) {
        newSorting.push({ propName: propName, direction: 'asc' });
      }

      let sortQueryParam = serializeSortingParam(newSorting, this.get('sortDefaultValue'));
      this.set('sort', sortQueryParam);
    }
  },

  /**
    Get next sorting direction.

    @method _getNextSortDirection
    @param {String} currentDirection Current sorting direction.
    @return {String} Sorting direction.
    @private
  */
  _getNextSortDirection: function(currentDirection) {
    let ret;
    switch (currentDirection) {
      case 'asc':
        ret = 'desc';
        break;
      case 'desc':
        ret = 'none';
        break;
      default: ret = 'asc';
    }
    return ret;
  },
});