APIs

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

import Mixin from '@ember/object/mixin';
import { assert } from '@ember/debug';
import { typeOf, isNone } from '@ember/utils';
import { get } from '@ember/object';
import { A, isArray } from '@ember/array';

/**
  Mixin containing logic which forces assertion exceptions
  if handlers for required actions are not defined.

  @class RequiredActionsMixin
  @extends <a href="https://www.emberjs.com/api/ember/release/classes/Mixin">Mixin</a>
*/
export default Mixin.create({
  /**
    Component's required actions names.
    For actions enumerated in this array an assertion exceptions will be thrown,
    if actions handlers are not defined for them.

    @property _requiredActions
    @type String[]
    @default null
  */
  _requiredActionNames: null,

  /**
    Returns flag, indicating whether action handler is defined, for action with the specified name, or not.

    @method _actionHandlerIsDefined
    @param {Object} options Method options
    @param {String} options.actionName Name of component's action for which handler's existence this method should check.
    @returns {Boolean} Flag, indicating whether action handler is defined, for action with the specified name, or not.
    @private
  */
  _actionHandlerIsDefined(options) {
    options = options || {};
    let actionName = get(options, 'actionName');

    return typeOf(this.get(`attrs.${actionName}`)) === 'function' ||
      typeOf(this.get(`attrs.${actionName}`)) === 'string';
  },

  /**
    Initializes required actions logic.
  */
  init() {
    this._super(...arguments);

    let originalSendDynamicAction = this.get('sendDynamicAction');

    // Override 'sendAction' method to add some custom logic.
    this.sendDynamicAction = (...args) => {
      let actionName = args[0];

      if (!isNone(originalSendDynamicAction)){
        originalSendDynamicAction.apply(this, args);
      }

      let requiredActionNames = this.get('_requiredActionNames');
      assert(
        `Wrong type of parent component\`s \`_requiredActionNames\` propery: ` +
        `actual type is ${typeOf(requiredActionNames)}, but \`array\` is expected.`,
        isNone(requiredActionNames) || isArray(requiredActionNames));

      // If no required actions names defined, break custom 'sendAction' logic then.
      if (!isArray(requiredActionNames)) {
        return;
      }

      // Throw assertion failed exception, if action handler is not defined for required action.
      assert(
        `Handler for required \`${actionName}\` action is not defined in ${this}`,
        !A(requiredActionNames).includes(actionName) || this._actionHandlerIsDefined({ actionName: actionName }));
    };
  }
});