Moving Element dependency from Request.js to Request.HTML.js and adjusted scripts...
[mootools.git] / Source / Request / Request.js
blob42fd8cf488bea3e7316c7f02c4adb368739a5943
1 /*
2 Script: Request.js
3         Powerful all purpose Request Class. Uses XMLHTTPRequest.
5 License:
6         MIT-style license.
7 */
9 var Request = new Class({
11         Implements: [Chain, Events, Options],
13         options: {/*
14                 onRequest: $empty,
15                 onComplete: $empty,
16                 onCancel: $empty,
17                 onSuccess: $empty,
18                 onFailure: $empty,
19                 onException: $empty,*/
20                 url: '',
21                 data: '',
22                 headers: {
23                         'X-Requested-With': 'XMLHttpRequest',
24                         'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
25                 },
26                 async: true,
27                 format: false,
28                 method: 'post',
29                 link: 'ignore',
30                 isSuccess: null,
31                 emulation: true,
32                 urlEncoded: true,
33                 encoding: 'utf-8',
34                 evalScripts: false,
35                 evalResponse: false,
36                 noCache: false
37         },
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);
44         },
46         onStateChange: function(){
47                 if (this.xhr.readyState != 4 || !this.running) return;
48                 this.running = false;
49                 this.status = 0;
50                 $try(function(){
51                         this.status = this.xhr.status;
52                 }.bind(this));
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);
56                 } else {
57                         this.response = {text: null, xml: null};
58                         this.failure();
59                 }
60                 this.xhr.onreadystatechange = $empty;
61         },
63         isSuccess: function(){
64                 return ((this.status >= 200) && (this.status < 300));
65         },
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);
70         },
72         success: function(text, xml){
73                 this.onSuccess(this.processScripts(text), xml);
74         },
76         onSuccess: function(){
77                 this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain();
78         },
80         failure: function(){
81                 this.onFailure();
82         },
84         onFailure: function(){
85                 this.fireEvent('complete').fireEvent('failure', this.xhr);
86         },
88         setHeader: function(name, value){
89                 this.headers.set(name, value);
90                 return this;
91         },
93         getHeader: function(name){
94                 return $try(function(){
95                         return this.xhr.getResponseHeader(name);
96                 }.bind(this));
97         },
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;
104                 }
105                 return false;
106         },
108         send: function(options){
109                 if (!this.check(arguments.callee, options)) return this;
110                 this.running = true;
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);
122                 }
124                 if (this.options.format){
125                         var format = 'format=' + this.options.format;
126                         data = (data) ? format + '&' + data : format;
127                 }
129                 if (this.options.emulation && ['put', 'delete'].contains(method)){
130                         var _method = '_method=' + method;
131                         data = (data) ? _method + '&' + data : _method;
132                         method = 'post';
133                 }
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);
138                 }
140                 if(this.options.noCache) {
141                         var noCache = "noCache=" + new Date().getTime();
142                         data = (data) ? noCache + '&' + data : noCache;
143                 }
146                 if (data && method == 'get'){
147                         url = url + (url.contains('?') ? '&' : '?') + data;
148                         data = null;
149                 }
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){
157                         try {
158                                 this.xhr.setRequestHeader(key, value);
159                         } catch (e){
160                                 this.fireEvent('exception', [key, value]);
161                         }
162                 }, this);
164                 this.fireEvent('request');
165                 this.xhr.send(data);
166                 if (!this.options.async) this.onStateChange();
167                 return this;
168         },
170         cancel: function(){
171                 if (!this.running) return this;
172                 this.running = false;
173                 this.xhr.abort();
174                 this.xhr.onreadystatechange = $empty;
175                 this.xhr = new Browser.Request();
176                 this.fireEvent('cancel');
177                 return this;
178         }
182 (function(){
184 var methods = {};
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()}));
189         };
192 Request.implement(methods);
194 })();