Source: core/Ajax.js

/*
 * src/core/Ajax.js
 * Author: H.Alper Tuna <halpertuna@gmail.com>
 * Date: 08.08.2016
 */

'use strict';

define([
    './Utils', './EventHandler'
], function(
    Utils, EventHandler
){
    function readyStateChange(){
        var xhttp = this.get('xhttp');
        if(xhttp.readyState == 4){
            //"always" closes connection and "success" may open new connection, so to prevent excessing maxConnection, always is at top of other triggers
            this.emit('always', xhttp.responseText);

            var fail = false;
            if(xhttp.status == 200){
                if(this.get('events').success.length){
                    var json;
                    try{
                        json = JSON.parse(xhttp.responseText);
                    }catch(e){
                        fail = true;
                    }
                    if(!fail)
                        this.emit('success', json);
                }
            }else fail = true;

            if(fail)
                this.emit('fail', xhttp.responseText);
        }
    }

    function parse(key, value, result){
        if(Utils.isArray(value)){
            key += '[]';
            for(var i in value)
                parse(key, value[i], result);
        }else if(Utils.isObject(value)){
            for(var i in value)
                parse(key + '[' + i + ']', value[i], result);
        }else
            result.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
    }

    function toParam(object){
        var result = [];

        for(var key in object){
            var value = object[key];
            parse(key, value, result)
        }

        return result.join('&');
    }

    return EventHandler.extend(/** @lends core/Ajax# */{
        'connectionIsOpen': false,

        /**
         * Ajax component class.
         * @constructs
         * @param {string} url - Url address.
         * @augments ui/EventHandler
         */
        'init': function(url){
            /**
             * On send event.
             * @event core/Ajax.core/Ajax:send
             */
            /**
             * On respond is successful event.
             * @event core/Ajax.core/Ajax:success
             * @param {Object} Responded json object
             */
            /**
             * On respond is fail event.
             * @event core/Ajax.core/Ajax:fail
             * @param {string} Responded non-parsed text.
             */
            /**
             * On respond is got event.
             * @event core/Ajax.core/Ajax:always
             * @param {string} Responded non-parsed text.
             */
            /**
             * On reached maximum connection event.
             * @event core/Ajax.core/Ajax:maxConnection
             */
            this.handle('send');
            this.handle('success');
            this.handle('fail');
            this.handle('always');
            this.handle('maxConnection');

            this.on('send', this.set.bind(this, 'connectionIsOpen', true));
            this.on('always', this.set.bind(this, 'connectionIsOpen', false));

            //TODO debug tool
            this.on('fail', function(c){
                console.warn('Response for ajax has fail: "' + c + '"');
            });
            //TODO debug tool
            this.on('maxConnection', function(c){
                console.warn('Reached max connection.');
            });

            var xhttp;
            if(window.XMLHttpRequest)
                xhttp = new XMLHttpRequest();
            else
                //For IE6, IE5
                xhttp = new ActiveXObject("Microsoft.XMLHTTP");
            this.set('xhttp', xhttp);
            if(url)
                this.setUrl(url);
        },
        'method': 'POST',

        /**
         * Sets request method.
         * @param {string} method - Method name.
         * @return {Object} Instance reference.
         */
        'setMethod': function(method){
            this.set('method', method);
            return this.ref;
        },
        /**
         * Sets url address.
         * @param {string} method - Url address.
         * @return {Object} Instance reference.
         */
        'setUrl': function(url){
            this.set('url', url);
            return this.ref;
        },
        /**
         * Sends ajax request.
         * @param {Object} [object] - Request data.
         * @return {Object} Instance reference.
         * @fires core/Ajax.core/Ajax:maxConnection
         * @fires core/AjaxGroup.core/AjaxGroup:maxConnection
         * @fires core/AjaxGroup.core/AjaxGroup:openedConnection
         * @fires core/Ajax.core/Ajax:send
         */
        'send': function(object){
            if(this.get('connectionIsOpen')){
                console.warn('Last connection hasn\'t closed yet.');

                return this.ref;
            }

            var ajaxGroup = this.get('ajaxGroup');
            if(ajaxGroup){
                if(!ajaxGroup.hasRoom()){
                    this.emit('maxConnection');
                    ajaxGroup.emit('maxConnection');
                    return this.ref;
                }
                ajaxGroup.emit('openedConnection');
            }

            var xhttp = this.get('xhttp');
            var params = toParam(object);
            var method = this.get('method');
            var url = this.get('url');
            if(method == 'GET') url += '?' + params;
            xhttp.open(method, url, true);
            xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
            xhttp.onreadystatechange = readyStateChange.bind(this);
            if(!object || method == 'GET') xhttp.send();
            else xhttp.send(params);

            this.emit('send');

            return this.ref;
        },

        'bound': false,
        /**
         * Binds to an AjaxGroup to work with other Ajaxs.
         * @param {core/AjaxGroup} ajaxGroup - Ajax group to bind.
         * @return {Object} Instance reference.
         */
        'bind': function(ajaxGroup){
            if(this.get('bound')){
                //TODO error
                throw 'This ajax instance is already bound a group.';
                return this.ref;
            }

            this.set('bound', true);
            this.set('ajaxGroup', ajaxGroup);
            this.on('always', ajaxGroup.emit.bind(ajaxGroup, 'closedConnection'));
            return this.ref;
        }
    })
})