Source: og/ajax.js

/**
 * @module og/ajax
 */

"use strict";

/**
 * Ajax parameters.
 * @namespace og.ajax
 */
const ajax = {
    /**
     * Ajax ready state result.
     * @enum
     */
    ReadyState: {
        Uninitialized: 0,
        Loading: 1,
        Loaded: 2,
        Interactive: 3,
        Complete: 4
    },
    /**
     * Ajax status code.
     * @enum
     */
    Status: {
        OK: 200,
        Created: 201,
        Accepted: 202,
        NoContent: 204,
        BadRequest: 400,
        Forbidden: 403,
        NotFound: 404,
        Gone: 410,
        ServerError: 500
    },
    /**
     * Ajax query method.
     * @enum
     */
    Method: {
        Get: "GET",
        Post: "POST"
    },
    /**
     * Ajax query type is asynchronous.
     * @type {boolean}
     */
    Asynchronous: true,
    /**
     * Ajax query type is synchronous.
     * @type {boolean}
     */
    Synchronous: false
};

/**
 * Xhr object that returned by ajax query.
 * @class
 * @param {Object} xhr - Current ActiveXObject object.
 */
const Xhr = function (xhr) {
    /**
     * ActiveXObject object.
     * @private
     * @type {Object}
     */
    var _xhr = xhr;

    /**
     * Aborts current ajax.
     * @public
     */
    this.abort = function () {
        _xhr.aborted = true;
        _xhr.abort();
    };
};

const defaultParams = {
    type: ajax.Method.Get,
    async: ajax.Asynchronous,
    data: null,
    sender: null,
    responseType: "text"
};

/**
 * Send an ajax request.
 * @function
 * @param {string} url - Url path.
 * @param {Object} [params] - Ajax parameters:
 * @param {ajax.Method|string} [params.type] - 'POST' or 'GET' ajax method. 'GET' is default.
 * @param {boolean} [params.async] - Asynchronous ajax flag. True is default.
 * @param {Object} [params.data] - Qery data.
 * @param {Object} [params.sender] - Sender object, that success callback binded with. ActiveXObject is default.
 * @param {string} [params.responseType] - Responce data type. Culd be 'text', 'json', 'jsonp', 'html'. 'text' is default.
 * @param {ajax.Xhr~successCallback} [params.success] - The callback that handles the success response.
 * @param {ajax.Xhr~errorCallback} [params.error] - The callback that handles the failed response.
 * @param {ajax.Xhr~abortCallback} [params.abort] - The callback that handles aborted requests.
 * @returns {ajax.Xhr} - Returns object that could be aborted.
 */
ajax.request = function (url, params) {
    params = params || {};

    var p = {},
        i;

    for (i in defaultParams) {
        p[i] = defaultParams[i];
    }

    for (i in params) {
        p[i] = params[i];
    }

    p.data = params.data;

    var xhr = new XMLHttpRequest();

    var customXhr = new Xhr(xhr);

    var body = null,
        d;

    if (p.type === ajax.Method.Post) {
        if (p.data) {
            body = "";
            for (let key in p.data) {
                d = p.data[key];
                body +=
                    key +
                    "=" +
                    encodeURIComponent(d instanceof Object ? JSON.stringify(d) : d) +
                    "&";
            }
            body = body.slice(0, -1);
        }
        xhr.open(p.type, url, p.async);
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    } else if (p.data) {
        var tail = "?";
        for (let key in p.data) {
            d = p.data[key];
            tail +=
                key + "=" + encodeURIComponent(d instanceof Object ? JSON.stringify(d) : d) + "&";
        }
        tail = tail.slice(0, -1);
        xhr.open(p.type, url + tail, p.async);
    } else {
        xhr.open(p.type, url, p.async);
    }

    if (p.async) {
        xhr.responseType = p.responseType;
    }

    xhr.overrideMimeType("text/plain");

    xhr.onreadystatechange = function () {
        if (xhr.readyState === ajax.ReadyState.Complete) {
            if (xhr.status === ajax.Status.OK) {
                if (params.success) {
                    /**
                     * Success callback.
                     * @callback ajax.Xhr~successCallback
                     * @param {Object} Response data
                     */
                    params.success.call(params.sender || customXhr, xhr.response);
                }
            } else if (xhr.aborted) {
                /**
                 * Abort callback.
                 * @callback ajax.Xhr~abortCallback
                 * @param {Object} Response data
                 * @param {Object} Status object
                 */
                params.abort &&
                    params.abort.call(params.sender || customXhr, xhr.response, xhr.status);
            } else {
                /**
                 * Error callback.
                 * @callback ajax.Xhr~errorCallback
                 * @param {Object} Response data
                 * @param {Object} Status object
                 */
                params.error &&
                    params.error.call(params.sender || customXhr, xhr.response, xhr.status);
            }
            delete xhr["onreadystatechange"];
            xhr.onreadystatechange = null;
            xhr = null;
        } else {
            // still loading
        }
    };

    xhr.send(body);

    return customXhr;
};

export { ajax };