Hironori Yoshida - JSONScriptRequest-0.01

Documentation | Source

NAME

JSONScriptRequest - Call JSONP using script element like XMLHttpRequest

SYNOPSIS

  var req = new JSONScriptRequest();
  req.open('GET', 'http://www.example.com/jsonp');
  req.onreadystatechange = function() {
      if (req.readyState == 4) {
          alert(req.responseJSON);
      }
  };
  req.send(null);

DESCRIPTION

See the document of XMLHttpRequest.

Class Properties

responseJSON

  var json = req.responseJSON;

This attributes represents the response as a JSON object. NULL if the request is unsuccessful or has not yet been sent.

Constructor

JSONScriptRequest({...})

The following values can be specified for the argument.

callback_param

The name of the callback parameter key. Default is 'callback'.

TODO

Implement the features that is not implemented yet.

Change throw object to an exception class from a string.

SEE ALSO

XULPlanet http://www.xulplanet.com/references/objref/XMLHttpRequest.html

AUTHOR

Hironori Yoshida <yoshida@cpan.org>

COPYRIGHT

  Copyright (c) 2006, Hironori Yoshida <yoshida@cpan.org>. All rights reserved.
  This module is free software; you can redistribute it and/or modify it
  under the terms of the Artistic license. Or whatever license I choose,
  which I will do instead of keeping this documentation like it is.
var JSONScriptRequest = function (args) {
    if (args) {
        if (args['callback_param']) {
            this._callback_param = args['callback_param'];
        }
    }
    return;
}

JSONScriptRequest.VERSION = 0.01;

JSONScriptRequest._dispatchers = [];

JSONScriptRequest.prototype = {
    _id: null,
    _script: null,
    _callback_param: 'callback',
    multipart: false,
    onreadystatechange: null,
    readyState: 0,
    responseText: null,
    responseJSON: null,
    status: 0,
    statusText: '',

    _readystatechange: function(readyState) {
        if (this.readyState == readyState) {
            // it does not change but do nothing to follow to
            // ActiveXObject of IE and XMLHttpRequest of Firefox.
        }
        this.readyState = readyState;
        if (this.onreadystatechange) {
            this.onreadystatechange();
        }
        return;
    },

    _createDispatcher: function() {
        for (this._id = 0; this._id < JSONScriptRequest._dispatchers.length; this._id++) {
            if ( !JSONScriptRequest._dispatchers[this._id] ) {
                break;
            }
        }

        var owner = this;
        JSONScriptRequest._dispatchers[this._id] = function(json) {
            if (owner.multipart) {
                throw 'Not implemented yet [JSONScriptRequest._dispatchers]';
            }
            owner._readystatechange(2);

            owner.responseText = json.toSource().replace(/^\(/, '').replace(/\)$/, '');
            owner._readystatechange(3);

            owner.responseJSON = json;
            owner._readystatechange(4);

            JSONScriptRequest._dispatchers[owner._id] = null;
            owner._id = null;
            return;
        };
        return;
    },

    abort: function() {
        if (this._id != null) {
            var id = this._id;
            JSONScriptRequest._dispatchers[id] = function(json) {
                JSONScriptRequest._dispatchers[id] = null;
            };
            this._id = null
        }
        return;
    },

    addEventListener: function(type, listener, useCapture) {
        throw 'Not implemented yet [JSONScriptRequest.addEventListener]';
        return;
    },

    dispatchEvent: function(evt) {
        throw 'Not implemented yet [JSONScriptRequest.dispatchEvent]';
        return false;
    },

    getAllResponseHeaders: function() {
        return '';
    },

    getResponseHeader: function(header) {
        return '';
    },

    open: function(method, url) {
        if ( arguments.length < 2 ) {
            throw 'Not enough arguments [JSONScriptRequest.open]';
        }
        var async = (arguments[2] != null) ? arguments[2] : true;
        var user = arguments[3];
        var password = arguments[4];
        this.openRequest(method, url, async, user, password);
        return;
    },

    openRequest: function(method, url, async, user, password) {
        if (arguments.length < 3) {
            throw 'Not enough arguments [JSONScriptRequest.openRequest]';
        }

        this.abort();

        // url
        if (!url) {
            throw 'Invalid url [JSONScriptRequest.openRequest]';
        }

        // method
        var http_re = new RegExp('^https?://', 'i');
        if (url.match(http_re) || location.href.match(http_re))  {
            method = method.toUpperCase();
            if (method != 'GET') {
                throw 'Invalid method [JSONScriptRequest.openRequest]';
            }
        }

        // async
        if (this.multipart && !async) {
            throw 'async must be true [JSONScriptRequest.openRequest]';
        }
        if (!async) {
            throw 'Not implemented yet [JSONScriptRequest.openRequest]';
        }

        // user, password
        if ( user || password ) {
            // This will not work.
            var userinfo = ( user ? user : '' ) + ':' + ( password ? password : '' );
            url.replace(new RegExp('(https?://)(.+)', 'i'), RegExp.$1 + userinfo + '@' + RegExp.$2);
        }

        // process
        this._createDispatcher();
        var queries = [];
        queries.push(this._callback_param + '=JSONScriptRequest._dispatchers[' + this._id + ']');

        url += (url.match(/\?/) ? '&' : '?') + queries.join('&');

        this._script = document.createElement('script');
        this._script.src = url;

        this._readystatechange(1);
        return;
    },

    overrideMimeType: function(mimetype) {
        throw 'Not implemented yet [JSONScriptRequest.overrideMimeType]';
        return;
    },

    removeEventListener: function(type, listener, useCapture) {
        throw 'Not implemented yet [JSONScriptRequest.removeEventListener]';
        return;
    },

    send: function(body) {
        if (this.readyState != 1) {
            throw 'Not Initialized [JSONScriptRequest.send]';
        }
        this._readystatechange(1);

        // body
        if (body) {
            if (typeof body != 'string') {
                var NODE_DOCUMENT = 9;
                if (body.nodeType == NODE_DOCUMENT) {
                    throw 'Not implemented yet [JSONScriptRequest.send]';
                } else if (typeof body.read == 'function') {
                    throw 'Not implemented yet [JSONScriptRequest.send]';
                }
            }
            this._script.src += '&' + body;
        }

        // process
        this._script.type = this._script.type || 'text/javascript';
        this._script.charset = this._script.charset || 'UTF-8';

        var head = document.getElementsByTagName('head')[0];
        head.appendChild(this._script);
        head.removeChild(this._script);
        this._script = null;

        return;
    },

    setRequestHeader: function(header, value) {
        if (this.readyState != 1) {
            throw 'Not Initialized [JSONScriptRequest.setRequestHeader]';
        }


        if ( header.toUpperCase() == 'ACCEPT' ) {
            this._script.type = value;
        }
        else if ( header.toUpperCase() == 'ACCEPT-CHARSET' ) {
            this._script.charset = value;
        }
        else {
            throw 'Invalid arguments';
        }
        return;
    }

};

/*

=head1 NAME

JSONScriptRequest - Call JSONP using script element like XMLHttpRequest

=head1 SYNOPSIS

  var req = new JSONScriptRequest();
  req.open('GET', 'http://www.example.com/jsonp');
  req.onreadystatechange = function() {
      if (req.readyState == 4) {
          alert(req.responseJSON);
      }
  };
  req.send(null);

=head1 DESCRIPTION

See the document of XMLHttpRequest.

=head2 Class Properties

=head3 responseJSON

  var json = req.responseJSON;

This attributes represents the response as a JSON object. NULL if the request is unsuccessful or has not yet been sent.

=head2 Constructor

=head3 JSONScriptRequest({...})

The following values can be specified for the argument.

=over

=item callback_param

The name of the callback parameter key. Default is 'callback'.

=back

=head1 TODO

=over

=item Implement the features that is not implemented yet.

=item Change throw object to an exception class from a string.

=back

=head1 SEE ALSO

XULPlanet
L<http://www.xulplanet.com/references/objref/XMLHttpRequest.html>

=head1 AUTHOR

Hironori Yoshida <yoshida@cpan.org>

=head1 COPYRIGHT

  Copyright (c) 2006, Hironori Yoshida <yoshida@cpan.org>. All rights reserved.
  This module is free software; you can redistribute it and/or modify it
  under the terms of the Artistic license. Or whatever license I choose,
  which I will do instead of keeping this documentation like it is.

=cut

*/