3 Powerful all purpose Request Class. Uses XMLHTTPRequest.
9 var Request = new Class({
11 Implements: [Chain, Events, Options],
19 onException: $empty,*/
23 'X-Requested-With': 'XMLHttpRequest',
24 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
39 initialize: function(options){
40 this.xhr = new Browser.Request();
41 this.setOptions(options);
42 this.options.isSuccess = this.options.isSuccess || this.isSuccess;
43 this.headers = new Hash(this.options.headers);
46 onStateChange: function(){
47 if (this.xhr.readyState != 4 || !this.running) return;
51 this.status = this.xhr.status;
53 if (this.options.isSuccess.call(this, this.status)){
54 this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML};
55 this.success(this.response.text, this.response.xml);
57 this.response = {text: null, xml: null};
60 this.xhr.onreadystatechange = $empty;
63 isSuccess: function(){
64 return ((this.status >= 200) && (this.status < 300));
67 processScripts: function(text){
68 if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text);
69 return text.stripScripts(this.options.evalScripts);
72 success: function(text, xml){
73 this.onSuccess(this.processScripts(text), xml);
76 onSuccess: function(){
77 this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain();
84 onFailure: function(){
85 this.fireEvent('complete').fireEvent('failure', this.xhr);
88 setHeader: function(name, value){
89 this.headers.set(name, value);
93 getHeader: function(name){
94 return $try(function(){
95 return this.xhr.getResponseHeader(name);
99 check: function(caller){
100 if (!this.running) return true;
101 switch (this.options.link){
102 case 'cancel': this.cancel(); return true;
103 case 'chain': this.chain(caller.bind(this, Array.slice(arguments, 1))); return false;
108 send: function(options){
109 if (!this.check(arguments.callee, options)) return this;
112 var type = $type(options);
113 if (type == 'string' || type == 'element') options = {data: options};
115 var old = this.options;
116 options = $extend({data: old.data, url: old.url, method: old.method}, options);
117 var data = options.data, url = options.url, method = options.method;
119 switch ($type(data)){
120 case 'element': data = $(data).toQueryString(); break;
121 case 'object': case 'hash': data = Hash.toQueryString(data);
124 if (this.options.format){
125 var format = 'format=' + this.options.format;
126 data = (data) ? format + '&' + data : format;
129 if (this.options.emulation && ['put', 'delete'].contains(method)){
130 var _method = '_method=' + method;
131 data = (data) ? _method + '&' + data : _method;
135 if (this.options.urlEncoded && method == 'post'){
136 var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
137 this.headers.set('Content-type', 'application/x-www-form-urlencoded' + encoding);
140 if(this.options.noCache) {
141 var noCache = "noCache=" + new Date().getTime();
142 data = (data) ? noCache + '&' + data : noCache;
146 if (data && method == 'get'){
147 url = url + (url.contains('?') ? '&' : '?') + data;
152 this.xhr.open(method.toUpperCase(), url, this.options.async);
154 this.xhr.onreadystatechange = this.onStateChange.bind(this);
156 this.headers.each(function(value, key){
158 this.xhr.setRequestHeader(key, value);
160 this.fireEvent('exception', [key, value]);
164 this.fireEvent('request');
166 if (!this.options.async) this.onStateChange();
171 if (!this.running) return this;
172 this.running = false;
174 this.xhr.onreadystatechange = $empty;
175 this.xhr = new Browser.Request();
176 this.fireEvent('cancel');
185 ['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){
186 methods[method] = function(){
187 var params = Array.link(arguments, {url: String.type, data: $defined});
188 return this.send($extend(params, {method: method.toLowerCase()}));
192 Request.implement(methods);