Merge pull request #1780 from dibdot/adblock
[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                 xhr.open('GET', url, true);
58
59                 if (!isNaN(timeout))
60                         xhr.timeout = timeout;
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                 xhr.open('POST', url, true);
96
97                 if (!isNaN(timeout))
98                         xhr.timeout = timeout;
99
100                 xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
101                 xhr.send(code);
102         }
103
104         this.cancel = function()
105         {
106                 this._xmlHttp.onreadystatechange = function(){};
107                 this._xmlHttp.abort();
108         }
109
110         this.send_form = function(form,callback,extra_values)
111         {
112                 var code = '';
113
114                 for (var i = 0; i < form.elements.length; i++)
115                 {
116                         var e = form.elements[i];
117
118                         if (e.options)
119                         {
120                                 code += (code ? '&' : '') +
121                                         form.elements[i].name + '=' + encodeURIComponent(
122                                                 e.options[e.selectedIndex].value
123                                         );
124                         }
125                         else if (e.length)
126                         {
127                                 for (var j = 0; j < e.length; j++)
128                                         if (e[j].name) {
129                                                 code += (code ? '&' : '') +
130                                                         e[j].name + '=' + encodeURIComponent(e[j].value);
131                                         }
132                         }
133                         else
134                         {
135                                 code += (code ? '&' : '') +
136                                         e.name + '=' + encodeURIComponent(e.value);
137                         }
138                 }
139
140                 if (typeof extra_values == 'object')
141                         for (var key in extra_values)
142                                 code += (code ? '&' : '') +
143                                         key + '=' + encodeURIComponent(extra_values[key]);
144
145                 return(
146                         (form.method == 'get')
147                                 ? this.get(form.getAttribute('action'), code, callback)
148                                 : this.post(form.getAttribute('action'), code, callback)
149                 );
150         }
151
152         this._encode = function(obj)
153         {
154                 obj = obj ? obj : { };
155                 obj['_'] = Math.random();
156
157                 if (typeof obj == 'object')
158                 {
159                         var code = '';
160                         var self = this;
161
162                         for (var k in obj)
163                                 code += (code ? '&' : '') +
164                                         k + '=' + encodeURIComponent(obj[k]);
165
166                         return code;
167                 }
168
169                 return obj;
170         }
171 }
172
173 XHR.get = function(url, data, callback)
174 {
175         (new XHR()).get(url, data, callback);
176 }
177
178 XHR.poll = function(interval, url, data, callback, post)
179 {
180         if (isNaN(interval) || interval < 1)
181                 interval = 5;
182
183         if (!XHR._q)
184         {
185                 XHR._t = 0;
186                 XHR._q = [ ];
187                 XHR._r = function() {
188                         for (var i = 0, e = XHR._q[0]; i < XHR._q.length; e = XHR._q[++i])
189                         {
190                                 if (!(XHR._t % e.interval) && !e.xhr.busy())
191                                         e.xhr[post ? 'post' : 'get'](e.url, e.data, e.callback, e.interval * 1000 - 5);
192                         }
193
194                         XHR._t++;
195                 };
196         }
197
198         var e = {
199                 interval: interval,
200                 callback: callback,
201                 url:      url,
202                 data:     data,
203                 xhr:      new XHR()
204         };
205
206         XHR._q.push(e);
207         XHR.run();
208
209         return e;
210 }
211
212 XHR.stop = function(e)
213 {
214         for (var i = 0; XHR._q && XHR._q[i]; i++) {
215                 if (XHR._q[i] === e) {
216                         e.xhr.cancel();
217                         XHR._q.splice(i, 1);
218                         return true;
219                 }
220         }
221
222         return false;
223 }
224
225 XHR.halt = function()
226 {
227         if (XHR._i)
228         {
229                 /* show & set poll indicator */
230                 try {
231                         document.getElementById('xhr_poll_status').style.display = '';
232                         document.getElementById('xhr_poll_status_on').style.display = 'none';
233                         document.getElementById('xhr_poll_status_off').style.display = '';
234                 } catch(e) { }
235
236                 window.clearInterval(XHR._i);
237                 XHR._i = null;
238         }
239 }
240
241 XHR.run = function()
242 {
243         if (XHR._r && !XHR._i)
244         {
245                 /* show & set poll indicator */
246                 try {
247                         document.getElementById('xhr_poll_status').style.display = '';
248                         document.getElementById('xhr_poll_status_on').style.display = '';
249                         document.getElementById('xhr_poll_status_off').style.display = 'none';
250                 } catch(e) { }
251
252                 /* kick first round manually to prevent one second lag when setting up
253                  * the poll interval */
254                 XHR._r();
255                 XHR._i = window.setInterval(XHR._r, 1000);
256         }
257 }
258
259 XHR.running = function()
260 {
261         return !!(XHR._r && XHR._i);
262 }