text: import Component from '@ember/component';
  import {computed} from '@ember/object';
  import {isBlank} from '@ember/utils';
  import {reads} from '@ember/object/computed';
  import {task, timeout} from 'ember-concurrency';
  
  /**
   * Task Button works exactly like Spin button, but with one major difference:
   *
   * Instead of passing a "submitting" parameter (which is bound to the parent object),
   * you pass an ember-concurrency task. All of the "submitting" behavior is handled automatically.
   *
   * As another bonus, there's no need to handle canceling the promises when something
   * like a controller changes. Because the only task running is handled through this
   * component, all running promises will automatically be cancelled when this
   * component is removed from the DOM
   */
  const GhTaskButton = Component.extend({
      tagName: 'button',
      classNameBindings: [
          'isRunning:appear-disabled',
          'isIdleClass',
          'isRunningClass',
          'isSuccessClass',
          'isFailureClass'
      ],
      attributeBindings: ['disabled', 'form', 'type', 'tabindex'],
  
      task: null,
      taskArgs: undefined,
      disabled: false,
      defaultClick: false,
      buttonText: 'Save',
      idleClass: '',
      runningClass: '',
      showSuccess: true, // set to false if you want the spinner to show until a transition occurs
      successText: 'Saved',
      successClass: 'gh-btn-green',
      failureText: 'Retry',
      failureClass: 'gh-btn-red',
  
      // Allowed actions
      action: () => {},
  
      runningText: reads('buttonText'),
  
      // hasRun is needed so that a newly rendered button does not show the last
      // state of the associated task
      hasRun: computed('task.performCount', function () {
          return this.get('task.performCount') > this._initialPerformCount;
      }),
  
      isIdleClass: computed('isIdle', function () {
          return this.isIdle ? this.idleClass : '';
      }),
  
      isRunning: computed('task.last.isRunning', 'hasRun', 'showSuccess', function () {
          let isRunning = this.get('task.last.isRunning');
  
          if (this.hasRun && this.get('task.last.value') && !this.showSuccess) {
              isRunning = true;
          }
  
          return isRunning;
      }),
  
      isRunningClass: computed('isRunning', function () {
          return this.isRunning ? (this.runningClass || this.idleClass) : '';
      }),
  
      isSuccess: computed('hasRun', 'isRunning', 'task.last.value', function () {
          if (!this.hasRun || this.isRunning || !this.showSuccess) {
              return false;
          }
  
          let value = this.get('task.last.value');
          return !isBlank(value) && value !== false;
      }),
  
      isSuccessClass: computed('isSuccess', function () {
          return this.isSuccess ? this.successClass : '';
      }),
  
      isFailure: computed('hasRun', 'isRunning', 'isSuccess', 'task.last.error', function () {
          if (!this.hasRun || this.isRunning || this.isSuccess) {
              return false;
          }
  
          return this.get('task.last.error') !== undefined;
      }),
  
      isFailureClass: computed('isFailure', function () {
          return this.isFailure ? this.failureClass : '';
      }),
  
      isIdle: computed('isRunning', 'isSuccess', 'isFailure', function () {
          return !this.isRunning && !this.isSuccess && !this.isFailure;
      }),
  
      init() {
          this._super(...arguments);
          this._initialPerformCount = this.get('task.performCount');
      },
  
      click() {
          // let the default click bubble if defaultClick===true - useful when
          // you want to handle a form submit action rather than triggering a
          // task directly
          if (this.defaultClick) {
              if (!this.isRunning) {
                  this._restartAnimation.perform();
              }
              return;
          }
  
          // do nothing if disabled externally
          if (this.disabled) {
              return false;
          }
  
          let task = this.task;
          let taskName = this.get('task.name');
          let lastTaskName = this.get('task.last.task.name');
  
          // task-buttons are never disabled whilst running so that clicks when a
          // taskGroup is running don't get dropped BUT that means we need to check
          // here to avoid spamming actions from multiple clicks
          if (this.isRunning && taskName === lastTaskName) {
              return;
          }
  
          this.action();
          task.perform(this.taskArgs);
  
          this._restartAnimation.perform();
  
          // prevent the click from bubbling and triggering form actions
          return false;
      },
  
      // mouseDown can be prevented, this is useful for situations where we want
      // to avoid on-blur events triggering before the button click
      mouseDown(event) {
          if (this.disableMouseDown) {
              event.preventDefault();
          }
      },
  
      // when local validation fails there's no transition from failed->running
      // so we want to restart the retry spinner animation to show something
      // has happened when the button is clicked
      _restartAnimation: task(function* () {
          let elem = this.element.querySelector('.retry-animated');
          if (elem) {
              elem.classList.remove('retry-animated');
              yield timeout(10);
              elem.classList.add('retry-animated');
          }
      })
  });
  
  export default GhTaskButton;
  