Some status requests can take quite some time to finish, the LuCI DSL status information in particular. Since the polling loop code already takes care of not relaunching requests which are already running, increase the per iteration timeout to up to five times the poll interval. This should be sufficient to let most operations complete. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
265 lines
4.9 KiB
JavaScript
265 lines
4.9 KiB
JavaScript
/*
|
|
* xhr.js - XMLHttpRequest helper class
|
|
* (c) 2008-2010 Jo-Philipp Wich
|
|
*/
|
|
|
|
XHR = function()
|
|
{
|
|
this.reinit = function()
|
|
{
|
|
if (window.XMLHttpRequest) {
|
|
this._xmlHttp = new XMLHttpRequest();
|
|
}
|
|
else if (window.ActiveXObject) {
|
|
this._xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
|
|
}
|
|
else {
|
|
alert("xhr.js: XMLHttpRequest is not supported by this browser!");
|
|
}
|
|
}
|
|
|
|
this.busy = function() {
|
|
if (!this._xmlHttp)
|
|
return false;
|
|
|
|
switch (this._xmlHttp.readyState)
|
|
{
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
this.abort = function() {
|
|
if (this.busy())
|
|
this._xmlHttp.abort();
|
|
}
|
|
|
|
this.get = function(url,data,callback,timeout)
|
|
{
|
|
this.reinit();
|
|
|
|
var ts = Date.now();
|
|
var xhr = this._xmlHttp;
|
|
var code = this._encode(data);
|
|
|
|
url = location.protocol + '//' + location.host + url;
|
|
|
|
if (code)
|
|
if (url.substr(url.length-1,1) == '&')
|
|
url += code;
|
|
else
|
|
url += '?' + code;
|
|
|
|
xhr.open('GET', url, true);
|
|
|
|
if (!isNaN(timeout))
|
|
xhr.timeout = timeout;
|
|
|
|
xhr.onreadystatechange = function()
|
|
{
|
|
if (xhr.readyState == 4) {
|
|
var json = null;
|
|
if (xhr.getResponseHeader("Content-Type") == "application/json") {
|
|
try {
|
|
json = JSON.parse(xhr.responseText);
|
|
}
|
|
catch(e) {
|
|
json = null;
|
|
}
|
|
}
|
|
|
|
callback(xhr, json, Date.now() - ts);
|
|
}
|
|
}
|
|
|
|
xhr.send(null);
|
|
}
|
|
|
|
this.post = function(url,data,callback,timeout)
|
|
{
|
|
this.reinit();
|
|
|
|
var ts = Date.now();
|
|
var xhr = this._xmlHttp;
|
|
var code = this._encode(data);
|
|
|
|
xhr.onreadystatechange = function()
|
|
{
|
|
if (xhr.readyState == 4)
|
|
callback(xhr, null, Date.now() - ts);
|
|
}
|
|
|
|
xhr.open('POST', url, true);
|
|
|
|
if (!isNaN(timeout))
|
|
xhr.timeout = timeout;
|
|
|
|
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
|
xhr.send(code);
|
|
}
|
|
|
|
this.cancel = function()
|
|
{
|
|
this._xmlHttp.onreadystatechange = function(){};
|
|
this._xmlHttp.abort();
|
|
}
|
|
|
|
this.send_form = function(form,callback,extra_values)
|
|
{
|
|
var code = '';
|
|
|
|
for (var i = 0; i < form.elements.length; i++)
|
|
{
|
|
var e = form.elements[i];
|
|
|
|
if (e.options)
|
|
{
|
|
code += (code ? '&' : '') +
|
|
form.elements[i].name + '=' + encodeURIComponent(
|
|
e.options[e.selectedIndex].value
|
|
);
|
|
}
|
|
else if (e.length)
|
|
{
|
|
for (var j = 0; j < e.length; j++)
|
|
if (e[j].name) {
|
|
code += (code ? '&' : '') +
|
|
e[j].name + '=' + encodeURIComponent(e[j].value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
code += (code ? '&' : '') +
|
|
e.name + '=' + encodeURIComponent(e.value);
|
|
}
|
|
}
|
|
|
|
if (typeof extra_values == 'object')
|
|
for (var key in extra_values)
|
|
code += (code ? '&' : '') +
|
|
key + '=' + encodeURIComponent(extra_values[key]);
|
|
|
|
return(
|
|
(form.method == 'get')
|
|
? this.get(form.getAttribute('action'), code, callback)
|
|
: this.post(form.getAttribute('action'), code, callback)
|
|
);
|
|
}
|
|
|
|
this._encode = function(obj)
|
|
{
|
|
obj = obj ? obj : { };
|
|
obj['_'] = Math.random();
|
|
|
|
if (typeof obj == 'object')
|
|
{
|
|
var code = '';
|
|
var self = this;
|
|
|
|
for (var k in obj)
|
|
code += (code ? '&' : '') +
|
|
k + '=' + encodeURIComponent(obj[k]);
|
|
|
|
return code;
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
}
|
|
|
|
XHR.get = function(url, data, callback)
|
|
{
|
|
(new XHR()).get(url, data, callback);
|
|
}
|
|
|
|
XHR.poll = function(interval, url, data, callback, post)
|
|
{
|
|
if (isNaN(interval) || interval < 1)
|
|
interval = 5;
|
|
|
|
if (!XHR._q)
|
|
{
|
|
XHR._t = 0;
|
|
XHR._q = [ ];
|
|
XHR._r = function() {
|
|
for (var i = 0, e = XHR._q[0]; i < XHR._q.length; e = XHR._q[++i])
|
|
{
|
|
if (!(XHR._t % e.interval) && !e.xhr.busy())
|
|
e.xhr[post ? 'post' : 'get'](e.url, e.data, e.callback, e.interval * 1000 * 5 - 5);
|
|
}
|
|
|
|
XHR._t++;
|
|
};
|
|
}
|
|
|
|
var e = {
|
|
interval: interval,
|
|
callback: callback,
|
|
url: url,
|
|
data: data,
|
|
xhr: new XHR()
|
|
};
|
|
|
|
XHR._q.push(e);
|
|
|
|
return e;
|
|
}
|
|
|
|
XHR.stop = function(e)
|
|
{
|
|
for (var i = 0; XHR._q && XHR._q[i]; i++) {
|
|
if (XHR._q[i] === e) {
|
|
e.xhr.cancel();
|
|
XHR._q.splice(i, 1);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
XHR.halt = function()
|
|
{
|
|
if (XHR._i)
|
|
{
|
|
/* show & set poll indicator */
|
|
try {
|
|
document.getElementById('xhr_poll_status').style.display = '';
|
|
document.getElementById('xhr_poll_status_on').style.display = 'none';
|
|
document.getElementById('xhr_poll_status_off').style.display = '';
|
|
} catch(e) { }
|
|
|
|
window.clearInterval(XHR._i);
|
|
XHR._i = null;
|
|
}
|
|
}
|
|
|
|
XHR.run = function()
|
|
{
|
|
if (XHR._r && !XHR._i)
|
|
{
|
|
/* show & set poll indicator */
|
|
try {
|
|
document.getElementById('xhr_poll_status').style.display = '';
|
|
document.getElementById('xhr_poll_status_on').style.display = '';
|
|
document.getElementById('xhr_poll_status_off').style.display = 'none';
|
|
} catch(e) { }
|
|
|
|
/* kick first round manually to prevent one second lag when setting up
|
|
* the poll interval */
|
|
XHR._r();
|
|
XHR._i = window.setInterval(XHR._r, 1000);
|
|
}
|
|
}
|
|
|
|
XHR.running = function()
|
|
{
|
|
return !!(XHR._r && XHR._i);
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', XHR.run);
|