build: introduce luci-base
[project/luci.git] / modules / 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)
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                 xhr.onreadystatechange = function()
60                 {
61                         if (xhr.readyState == 4) {
62                                 var json = null;
63                                 if (xhr.getResponseHeader("Content-Type") == "application/json") {
64                                         try {
65                                                 json = eval('(' + xhr.responseText + ')');
66                                         }
67                                         catch(e) {
68                                                 json = null;
69                                         }
70                                 }
71
72                                 callback(xhr, json);
73                         }
74                 }
75
76                 xhr.send(null);
77         }
78
79         this.post = function(url,data,callback)
80         {
81                 this.reinit();
82
83                 var xhr  = this._xmlHttp;
84                 var code = this._encode(data);
85
86                 xhr.onreadystatechange = function()
87                 {
88                         if (xhr.readyState == 4)
89                                 callback(xhr);
90                 }
91
92                 xhr.open('POST', url, true);
93                 xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
94                 xhr.setRequestHeader('Content-length', code.length);
95                 xhr.setRequestHeader('Connection', 'close');
96                 xhr.send(code);
97         }
98
99         this.cancel = function()
100         {
101                 this._xmlHttp.onreadystatechange = function(){};
102                 this._xmlHttp.abort();
103         }
104
105         this.send_form = function(form,callback,extra_values)
106         {
107                 var code = '';
108
109                 for (var i = 0; i < form.elements.length; i++)
110                 {
111                         var e = form.elements[i];
112
113                         if (e.options)
114                         {
115                                 code += (code ? '&' : '') +
116                                         form.elements[i].name + '=' + encodeURIComponent(
117                                                 e.options[e.selectedIndex].value
118                                         );
119                         }
120                         else if (e.length)
121                         {
122                                 for (var j = 0; j < e.length; j++)
123                                         if (e[j].name) {
124                                                 code += (code ? '&' : '') +
125                                                         e[j].name + '=' + encodeURIComponent(e[j].value);
126                                         }
127                         }
128                         else
129                         {
130                                 code += (code ? '&' : '') +
131                                         e.name + '=' + encodeURIComponent(e.value);
132                         }
133                 }
134
135                 if (typeof extra_values == 'object')
136                         for (var key in extra_values)
137                                 code += (code ? '&' : '') +
138                                         key + '=' + encodeURIComponent(extra_values[key]);
139
140                 return(
141                         (form.method == 'get')
142                                 ? this.get(form.getAttribute('action'), code, callback)
143                                 : this.post(form.getAttribute('action'), code, callback)
144                 );
145         }
146
147         this._encode = function(obj)
148         {
149                 obj = obj ? obj : { };
150                 obj['_'] = Math.random();
151
152                 if (typeof obj == 'object')
153                 {
154                         var code = '';
155                         var self = this;
156
157                         for (var k in obj)
158                                 code += (code ? '&' : '') +
159                                         k + '=' + encodeURIComponent(obj[k]);
160
161                         return code;
162                 }
163
164                 return obj;
165         }
166 }
167
168 XHR.get = function(url, data, callback)
169 {
170         (new XHR()).get(url, data, callback);
171 }
172
173 XHR.poll = function(interval, url, data, callback)
174 {
175         if (isNaN(interval) || interval < 1)
176                 interval = 5;
177
178         if (!XHR._q)
179         {
180                 XHR._t = 0;
181                 XHR._q = [ ];
182                 XHR._r = function() {
183                         for (var i = 0, e = XHR._q[0]; i < XHR._q.length; e = XHR._q[++i])
184                         {
185                                 if (!(XHR._t % e.interval) && !e.xhr.busy())
186                                         e.xhr.get(e.url, e.data, e.callback);
187                         }
188
189                         XHR._t++;
190                 };
191         }
192
193         XHR._q.push({
194                 interval: interval,
195                 callback: callback,
196                 url:      url,
197                 data:     data,
198                 xhr:      new XHR()
199         });
200
201         XHR.run();
202 }
203
204 XHR.halt = function()
205 {
206         if (XHR._i)
207         {
208                 /* show & set poll indicator */
209                 try {
210                         document.getElementById('xhr_poll_status').style.display = '';
211                         document.getElementById('xhr_poll_status_on').style.display = 'none';
212                         document.getElementById('xhr_poll_status_off').style.display = '';
213                 } catch(e) { }
214
215                 window.clearInterval(XHR._i);
216                 XHR._i = null;
217         }
218 }
219
220 XHR.run = function()
221 {
222         if (XHR._r && !XHR._i)
223         {
224                 /* show & set poll indicator */
225                 try {
226                         document.getElementById('xhr_poll_status').style.display = '';
227                         document.getElementById('xhr_poll_status_on').style.display = '';
228                         document.getElementById('xhr_poll_status_off').style.display = 'none';
229                 } catch(e) { }
230
231                 /* kick first round manually to prevent one second lag when setting up
232                  * the poll interval */
233                 XHR._r();
234                 XHR._i = window.setInterval(XHR._r, 1000);
235         }
236 }
237
238 XHR.running = function()
239 {
240         return !!(XHR._r && XHR._i);
241 }