
/*

    ==========================
    TSF AJAX Javascript module
    ==========================

    - simple AJAX using a hash table
    - utf-8 should be used for non-ascii characters



    CLIENT SIDE SCRIPT:
    ===================

    <head>
    ...
    <script type="text/javascript" src="js/json.js"></script>
    <script type="text/javascript" src="js/tsfajax.js"></script>
    ...
    </head>

    <script type="text/javascript">
    if (AJAXAvailable()) {
        var data = { "echo" : "pokus", "name" : "John Smith", "city" : "York" };
        function readyFunc (result) { 
            alert(result["echo"]); 
        }
        var ajax = new AJAX();
        ajax.sendjson(readyFunc, url, data)

        // or you could use this for raw data without any json conversions:
        //
        // ajax.sendraw(readyObj, readyMethod, type, url, data, meta)
    }
    </script>



    PHP5 SERVER SIDE:
    ================

    - compile with the "json" extension

    $postdata = "";
    $in = fopen("php://input", "r");
    while(!feof($in)) { $postdata .= fread($in, 4096); }
    $in = json_decode($postdata, 1);

    $out = array(
        "echo" => $in["echo"],
    );
    header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); # disable IE caching
    header("Cache-Control: no-cache, must-revalidate");
    header("Pragma: no-cache");
    header("Content-Type: text/plain; charset=utf-8");
    print json_encode($out);



    PERL SERVER SIDE:
    =================

    - install the JSON cpan module

    use JSON;

    my $postdata;
    while (<STDIN>) { $postdata .= $_ }
    my $in = JSON::from_json($postdata, 1);

    my $out = {
        echo => $in->{echo},
    };

    print "Expires: Mon, 26 Jul 1997 05:00:00 GMT\n"; # disable IE caching
    print "Cache-Control: no-cache, must-revalidate\n";
    print "Pragma: no-cache\n";
    print "Content-Type: text/plain; charset=utf-8\n";
    print "\n"; # terminate headers
    print JSON::to_json($out);




    AUTHOR:
    =======

    Author: Tomas Styblo <tripie@cpan.org>
    License: GNU GPL
*/

/* plain function */
function AJAXAvailable() {
    return (window.ActiveXObject || window.XMLHttpRequest);
}

function AJAX() {
}

AJAX.prototype.available = function () {
    return AJAXAvailable();
}

AJAX.prototype.debug = function (msg) {
    var li = document.createElement("li");
    li.innerHTML = msg + "<br>\n";
    document.body.appendChild(li);
}

AJAX.prototype.sendjson = function (readyFunc, url, data, meta) {
    var r = new Object();
    r.ready = function (res) {
        var data = null;
        try {
            data = res.status ? res.data.parseJSON() : null;
        }   
        catch (e) {
            data = null;
        }   
        readyFunc.call(null, data, res.meta); 
    };  
    this.sendraw(r, r.ready, "POST", url, data.toJSONString(), meta);
}

AJAX.prototype.sendraw = function (readyObj, readyMethod, type, url, data, meta) {

    // add random string to the URL to prevent caching
    if (url.indexOf("?") == -1) {
        url += "?" + Math.random(); 
    }
    else {
        url += "&" + Math.random();
    }
    
    if (window.ActiveXObject) {
        this.httpRequestor = new ActiveXObject("Microsoft.XMLHTTP");
    }
    else if (window.XMLHttpRequest) {
        this.httpRequestor = new XMLHttpRequest();
    }
    else {
        throw "this browser has no AJAX implementation";
    }
    this.processingURL = url;
    this.meta = meta;
    this.httpRequestor.open(type, url, true);
    var thisclosure = this;
    this.httpRequestor.onreadystatechange = function () { thisclosure.handler(); };
    this.requestReadyObj = readyObj;
    this.requestReadyMethod = readyMethod;
    // this.httpRequestor.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    this.httpRequestor.setRequestHeader("Content-Type", "text/plain");
    this.httpRequestor.send(data);
    return true;
}

AJAX.prototype.handler = function () {
    if (this.httpRequestor.readyState == 4) {
        var input = this.httpRequestor.responseText;
        if (this.httpRequestor.status == 200) {
            this.requestReadyMethod.call(this.requestReadyObj, { 
                "status" : true,
                "data"   : input,
                "meta"   : this.meta
            });
        }
        else {
            var error = this.processingURL + ":" + this.httpRequestor.status + " " + this.httpRequestor.statusText + "\n\n" + input;
            this.requestReadyMethod.call(this.requestReadyObj, { 
                "status" : false,
                "error"  : error,
                "meta"   : this.meta
            });
        }
    }
}

