luci-mod-rpc: fix authentication via query string parameter
[project/luci.git] / modules / luci-base / htdocs / luci-static / resources / xhr.js
1 /*
2  * xhr.js - XMLHttpRequest helper class
3  * (c) 2008-2010 Jo-Philipp Wich
4  */
5
6 XHR = function()
7 {
8         this.reinit = function()
9         {
10                 if (window.XMLHttpRequest) {
11                         this._xmlHttp = new XMLHttpRequest();
12                 }
13                 else if (window.ActiveXObject) {
14                         this._xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
15                 }
16                 else {
17                         alert("xhr.js: XMLHttpRequest is not supported by this browser!");
18                 }
19         }
20
21         this.busy = function() {
22                 if (!this._xmlHttp)
23                         return false;
24
25                 switch (this._xmlHttp.readyState)
26                 {
27                         case 1:
28                         case 2:
29                         case 3:
30                                 return true;
31
32                         default:
33                                 return false;
34                 }
35         }
36
37         this.abort = function() {
38                 if (this.busy())
39                         this._xmlHttp.abort();
40         }
41
42         this.get = function(url,data,callback,timeout)
43         {
44                 this.reinit();
45
46                 var xhr  = this._xmlHttp;
47                 var code = this._encode(data);
48
49                 url = location.protocol + '//' + location.host + url;
50
51                 if (code)
52                         if (url.substr(url.length-1,1) == '&')
53                                 url += code;
54                         else
55                                 url += '?' + code;
56
57                 if (!isNaN(timeout))
58                         xhr.timeout = timeout;
59
60                 xhr.open('GET', url, true);
61
62                 xhr.onreadystatechange = function()
63                 {
64                         if (xhr.readyState == 4) {
65                                 var json = null;
66                                 if (xhr.getResponseHeader("Content-Type") == "application/json") {
67                                         try {
68                                                 json = eval('(' + xhr.responseText + ')');
69                                         }
70                                         catch(e) {
71                                                 json = null;
72                                         }
73                                 }
74
75                                 callback(xhr, json);
76                         }
77                 }
78
79                 xhr.send(null);
80         }
81
82         this.post = function(url,data,callback,timeout)
83         {
84                 this.reinit();
85
86                 var xhr  = this._xmlHttp;
87                 var code = this._encode(data);
88
89                 xhr.onreadystatechange = function()
90                 {
91                         if (xhr.readyState == 4)
92                                 callback(xhr);
93                 }
94
95                 if (!isNaN(timeout))
96                         xhr.timeout = timeout;
97
98                 xhr.open('POST', url, true);
99                 xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
100                 xhr.send(code);
101         }
102
103         this.cancel = function()
104         {
105                 this._xmlHttp.onreadystatechange = function(){};
106                 this._xmlHttp.abort();
107         }
108
109         this.send_form = function(form,callback,extra_values)
110         {
111                 var code = '';
112
113                 for (var i = 0; i < form.elements.length; i++)
114                 {
115                         var e = form.elements[i];
116
117                         if (e.options)
118                         {
119                                 code += (code ? '&' : '') +
120                                         form.elements[i].name + '=' + encodeURIComponent(
121                                                 e.options[e.selectedIndex].value
122                                         );
123                         }
124                         else if (e.length)
125                         {
126                                 for (var j = 0; j < e.length; j++)
127                                         if (e[j].name) {
128                                                 code += (code ? '&' : '') +
129                                                         e[j].name + '=' + encodeURIComponent(e[j].value);
130                                         }
131                         }
132                         else
133                         {
134                                 code += (code ? '&' : '') +
135                                         e.name + '=' + encodeURIComponent(e.value);
136                         }
137                 }
138
139                 if (typeof extra_values == 'object')
140                         for (var key in extra_values)
141                                 code += (code ? '&' : '') +
142                                         key + '=' + encodeURIComponent(extra_values[key]);
143
144                 return(
145                         (form.method == 'get')
146                                 ? this.get(form.getAttribute('action'), code, callback)
147                                 : this.post(form.getAttribute('action'), code, callback)
148                 );
149         }
150
151         this._encode = function(obj)
152         {
153                 obj = obj ? obj : { };
154                 obj['_'] = Math.random();
155
156                 if (typeof obj == 'object')
157                 {
158                         var code = '';
159                         var self = this;
160
161                         for (var k in obj)
162                                 code += (code ? '&' : '') +
163                                         k + '=' + encodeURIComponent(obj[k]);
164
165                         return code;
166                 }
167
168                 return obj;
169         }
170 }
171
172 XHR.get = function(url, data, callback)
173 {
174         (new XHR()).get(url, data, callback);
175 }
176
177 XHR.poll = function(interval, url, data, callback, post)
178 {
179         if (isNaN(interval) || interval < 1)
180                 interval = 5;
181
182         if (!XHR._q)
183         {
184                 XHR._t = 0;
185                 XHR._q = [ ];
186                 XHR._r = function() {
187                         for (var i = 0, e = XHR._q[0]; i < XHR._q.length; e = XHR._q[++i])
188                         {
189                                 if (!(XHR._t % e.interval) && !e.xhr.busy())
190                                         e.xhr[post ? 'post' : 'get'](e.url, e.data, e.callback, e.interval * 1000 - 5);
191                         }
192
193                         XHR._t++;
194                 };
195         }
196
197         var e = {
198                 interval: interval,
199                 callback: callback,
200                 url:      url,
201                 data:     data,
202                 xhr:      new XHR()
203         };
204
205         XHR._q.push(e);
206         XHR.run();
207
208         return e;
209 }
210
211 XHR.stop = function(e)
212 {
213         for (var i = 0; XHR._q && XHR._q[i]; i++) {
214                 if (XHR._q[i] === e) {
215                         e.xhr.cancel();
216                         XHR._q.splice(i, 1);
217                         return true;
218                 }
219         }
220
221         return false;
222 }
223
224 XHR.halt = function()
225 {
226         if (XHR._i)
227         {
228                 /* show & set poll indicator */
229                 try {
230                         document.getElementById('xhr_poll_status').style.display = '';
231                         document.getElementById('xhr_poll_status_on').style.display = 'none';
232                         document.getElementById('xhr_poll_status_off').style.display = '';
233                 } catch(e) { }
234
235                 window.clearInterval(XHR._i);
236                 XHR._i = null;
237         }
238 }
239
240 XHR.run = function()
241 {
242         if (XHR._r && !XHR._i)
243         {
244                 /* show & set poll indicator */
245                 try {
246                         document.getElementById('xhr_poll_status').style.display = '';
247                         document.getElementById('xhr_poll_status_on').style.display = '';
248                         document.getElementById('xhr_poll_status_off').style.display = 'none';
249                 } catch(e) { }
250
251                 /* kick first round manually to prevent one second lag when setting up
252                  * the poll interval */
253                 XHR._r();
254                 XHR._i = window.setInterval(XHR._r, 1000);
255         }
256 }
257
258 XHR.running = function()
259 {
260         return !!(XHR._r && XHR._i);
261 }