Show:
/**
 support ajax request in this module
 @module mixins
 @submodule ajax
 */
import Mixin from '@ember/object/mixin';
import { A, isArray } from '@ember/array';
import Evented from '@ember/object/evented';
import { isBlank, isNone } from '@ember/utils';
import { Promise } from 'rsvp';
import $ from 'jquery';

/**
 get request function used in ajax.request property
 @private
 */
const _get = function (url, options) {
  let self = this.parent;
  return self.ajax('get', url, options).then(
    function (data) {
      // eslint-disable-next-line no-useless-catch
      try {
        return self.getSerializer(data);
      } catch (e) {
        throw e;
      }
    },
    function (reason) {
      throw reason;
    }
  );
};

/**
 post request function used in ajax.request property
 @private
 */
const _post = function (url, options) {
  let self = this.parent;
  return self.ajax('post', url, options).then(
    function (data) {
      // eslint-disable-next-line no-useless-catch
      try {
        return self.postSerializer(data);
      } catch (e) {
        throw e;
      }
    },
    function (reason) {
      throw reason;
    }
  );
};

/**
 delete request function used in ajax.request property
 @private
 */
const _delete = function (url, options) {
  let self = this.parent;
  return self.ajax('delete', url, options).then(
    function (data) {
      // eslint-disable-next-line no-useless-catch
      try {
        return self.deleteSerializer(data);
      } catch (e) {
        throw e;
      }
    },
    function (reason) {
      throw reason;
    }
  );
};

/**
 put request function used in ajax.request property
 @private
 */
const _put = function (url, options) {
  let self = this.parent;
  return self.ajax('put', url, options).then(
    function (data) {
      // eslint-disable-next-line no-useless-catch
      try {
        return self.putSerializer(data);
      } catch (e) {
        throw e;
      }
    },
    function (reason) {
      throw reason;
    }
  );
};

/**
 wrap jquery ajax with Ember.RSVP.Promise, this mixin also has events like:
 - ajaxStart be trigged when ajax request start
 - ajaxDone  be trigged when ajax request finish (success or fails)
 - ajaxSuccess  be trigged when promise resovle success
 - ajaxError be trigged when ajax request fails
 - RESTSerializerError  be trigged error happen when response data serialize
 @public
 @class ajax
 */
export default Mixin.create(Evented, {
  /**
     wrapper all request method (get put post delete) into request object
     @property request
     @type Object
     @default {Object}
     */
  request: null,
  /**
     ajax request setting See http://devdocs.io/jquery/jquery.ajax
     @property ajaxSettings
     @type Object
     @default {dataType: 'json'}
     */
  // eslint-disable-next-line ember/avoid-leaking-state-in-ember-objects
  ajaxSettings: {
    dataType: 'json',
  },
  /**
     if contentType is application/json which method request data need to be serialized with json
     @property needSerializedMethod
     @type Object
     @default ['post', 'put']
     */
  needSerializedMethod: null,
  /**
     jquery ajax method wrapper, return promise
     @method ajax
     @param {String} method request method
     @param {String} url request url
     @param {Object} options ajax jquery ajax settings, see http://devdocs.io/jquery/jquery.ajax
     @return {Promise}
     */
  ajax: function (method, url, options) {
    let self = this,
      ajaxSettings = {};
    Object.assign(ajaxSettings, this.ajaxSettings);
    if (typeof options === 'object' && !isNone(options)) {
      Object.assign(ajaxSettings, options);
    }

    if (typeof method !== 'string' || isBlank(method)) {
      throw new Error(`ajax request method is invalid: ${method}`);
    }

    if (typeof url !== 'string' || isBlank(url)) {
      throw new Error(`ajax request url is invalid: ${url}`);
    }

    Object.assign(ajaxSettings, { type: method, url: url });
    if (
      ajaxSettings.contentType === 'application/json' &&
      ajaxSettings['data'] &&
      isArray(this.needSerializedMethod) &&
      this.needSerializedMethod.includes(method)
    ) {
      ajaxSettings['data'] = JSON.stringify(ajaxSettings['data']);
    }
    self.trigger('ajaxStart');
    return new Promise(function (resolve, reject) {
      // eslint-disable-next-line ember/no-jquery
      $.ajax(ajaxSettings)
        .done(function (data) {
          self.trigger('ajaxDone');
          try {
            resolve(self.RESTSerializer(data));
            self.trigger('ajaxSuccess');
          } catch (e) {
            self.trigger('RESTSerializerError', e);
            reject(e);
          }
        })
        .fail(function (jqXHR, responseText, errorThrown) {
          self.trigger('ajaxDone');
          console.log(jqXHR);
          console.log(ajaxSettings);
          let error = `${responseText} ${errorThrown}`;
          self.trigger('ajaxError', error, ajaxSettings, jqXHR);
          reject(new Error(error));
        });
    });
  },
  /**
     all ajax response data serializer
     @method RESTSerializer
     @param {Object} data response data
     @return serializer data
     */
  RESTSerializer: function (data) {
    console.log(
      'subclass override RESTSerializer for response data serializer'
    );
    return data;
  },
  /**
     get method response data serializer
     @method getSerializer
     @param {Object} data response data
     @return serializer data
     */
  getSerializer: function (data) {
    console.log(
      'subclass override getSerializer for get response data serializer'
    );
    return data;
  },
  /**
     post method response data serializer
     @method postSerializer
     @param {Object} data response data
     @return serializer data
     */
  postSerializer: function (data) {
    console.log(
      'subclass override postSerializer for post response data serializer'
    );
    return data;
  },
  /**
     put method response data serializer
     @method putSerializer
     @param {Object} data response data
     @return serializer data
     */
  putSerializer: function (data) {
    console.log(
      'subclass override putSerializer for put response data serializer'
    );
    return data;
  },
  /**
     delete method response data serializer
     @method deleteSerializer
     @param {Object} data response data
     @return serializer data
     */
  deleteSerializer: function (data) {
    console.log(
      'subclass override deleteSerializer for delete response data serializer'
    );
    return data;
  },
  init: function () {
    this._super(...arguments);
    let self = this;
    const request = {
      parent: self,
      get: _get,
      post: _post,
      put: _put,
      delete: _delete,
    };
    this.set('needSerializedMethod', A(['post', 'put']));
    this.set('request', request);
  },
});