function JsHttpRequest() { this._construct() }
(function() {
var COUNT = 0;
var PENDING = {};
var CACHE = {};
JsHttpRequest.dataReady = function(id, text, js) {
var th = PENDING[id];
delete PENDING[id];
if (th) {
delete th._xmlReq;
if (th.caching && th.hash) CACHE[th.hash] = [text, js];
th._dataReady(text, js);
} else if (th !== false) {
throw "JsHttpRequest.dataReady(): unknown pending id: " + id;
}
}
JsHttpRequest.query = function(url, content, onready, nocache) {
var req = new JsHttpRequest();
req.caching = !nocache;
req.onreadystatechange = function() {
if (req.readyState == 4) {
onready(req.responseJS, req.responseText);
}
}
req.open(null, url, true);
req.send(content);
},
JsHttpRequest.prototype = {
onreadystatechange: null,
readyState: 0,
responseText: null,
responseXML: null,
status: 200,
statusText: "OK",
responseJS: null,
session_name: "PHPSESSID",
caching: false,
loader: null,
_span: null,
_id: null,
_xmlReq: null,
_openArg: null,
_reqHeaders: null,
_maxUrlLen: 2000,
dummy: function() {},
abort: function() {
if (this._xmlReq) {
this._xmlReq.abort();
this._xmlReq = null;
}
this._cleanupScript();
this._changeReadyState(4, true);
},
open: function(method, url, asyncFlag, username, password) {
var sid = this._getSid();
if (sid) url += (url.indexOf('?')>=0? '&' : '?') + this.session_name + "=" + this.escape(sid);
this._openArg = {
method: (method||'').toUpperCase(),
url: url,
asyncFlag: asyncFlag,
username: username != null? username : '',
password: password != null? password : ''
};
this._id = null;
this._xmlReq = null;
this._reqHeaders = [];
this._changeReadyState(1, true);
return true;
},
send: function(content) {
this._changeReadyState(1, true);
var id = (new Date().getTime()) + "" + COUNT++;
var url = this._openArg.url;
var queryText = [];
var queryElem = [];
if (!this._hash2query(content, null, queryText, queryElem)) return;
var loader = (this.loader||'').toLowerCase();
var method = this._openArg.method;
var xmlReq = null;
if (queryElem.length && !loader) {
loader = 'form';
} else {
xmlReq = this._obtainXmlReq(id, url);
}
var fullGetUrl = url + (url.indexOf('?')>=0? '&' : '?') + queryText.join('&');
this.hash = null;
if (this.caching && !queryElem.length) {
this.hash = fullGetUrl;
if (CACHE[this.hash]) {
var c = CACHE[this.hash];
this._dataReady(c[0], c[1]);
return false;
}
}
var canSetHeaders = xmlReq && (window.ActiveXObject || xmlReq.setRequestHeader);
if (!loader) {
if (xmlReq) {
loader = 'xml';
switch (method) {
case "POST":
if (!canSetHeaders) {
loader = 'form';
}
break;
case "GET":
break;
default:
if (canSetHeaders) {
method = 'POST';
} else {
if (fullGetUrl.length > this._maxUrlLen) {
method = 'POST';
loader = 'form';
} else {
method = 'GET';
}
}
}
} else {
loader = 'script';
switch (method) {
case "POST":
loader = 'form';
break;
case "GET":
break;
default:
if (fullGetUrl.length > this._maxUrlLen) {
method = 'POST';
loader = 'form';
} else {
method = 'GET';
}
}
}
} else if (!method) {
switch (loader) {
case 'form':
method = 'POST';
break;
case 'script':
method = 'GET';
break;
default:
if (canSetHeaders) {
method = 'POST';
} else {
method = 'GET';
}
}
}
var requestBody = null;
if (method == 'GET') {
url = fullGetUrl;
if (url.length > this._maxUrlLen) return this._error('Cannot use so long query (URL is ' + url.length + ' byte(s) length) with GET request.');
} else if (method == 'POST') {
requestBody = queryText.join('&');
} else {
return this._error('Unknown method: ' + method + '. Only GET and POST are supported.');
}
url = url + (url.indexOf('?')>=0? '&' : '?') + 'JsHttpRequest=' + id + '-' + loader;
PENDING[id] = this;
switch (loader) {
case 'xml':
if (!xmlReq) return this._error('Cannot use XMLHttpRequest or ActiveX loader: not supported');
if (method == "POST" && !canSetHeaders) return this._error('Cannot use XMLHttpRequest loader or ActiveX loader, POST method: headers setting is not supported');
if (queryElem.length) return this._error('Cannot use XMLHttpRequest loader: direct form elements using and uploading are not implemented');
this._xmlReq = xmlReq;
var a = this._openArg;
this._xmlReq.open(method, url, a.asyncFlag, a.username, a.password);
if (canSetHeaders) {
for (var i=0; i<this._reqHeaders.length; i++)
this._xmlReq.setRequestHeader(this._reqHeaders[i][0], this._reqHeaders[i][1]);
this._xmlReq.setRequestHeader('Content-Type', 'application/octet-stream');
}
return this._xmlReq.send(requestBody);
case 'script':
if (method != 'GET') return this._error('Cannot use SCRIPT loader: it supports only GET method');
if (queryElem.length) return this._error('Cannot use SCRIPT loader: direct form elements using and uploading are not implemented');
this._obtainScript(id, url);
return true;
case 'form':
if (!this._obtainForm(id, url, method, queryText, queryElem)) return null;
return true;
default:
return this._error('Unknown loader: ' + loader);
}
},
getAllResponseHeaders: function() {
if (this._xmlReq) return this._xmlReq.getAllResponseHeaders();
return '';
},
getResponseHeader: function(label) {
if (this._xmlReq) return this._xmlReq.getResponseHeader(label);
return '';
},
setRequestHeader: function(label, value) {
this._reqHeaders[this._reqHeaders.length] = [label, value];
},
_construct: function() {},
_dataReady: function(text, js) { with (this) {
if (text !== null || js !== null) {
status = 4;
responseText = responseXML = text;
responseJS = js;
} else {
status = 500;
responseText = responseXML = responseJS = null;
}
_changeReadyState(2);
_changeReadyState(3);
_changeReadyState(4);
_cleanupScript();
}},
_error: function(msg) {
alert(msg);
throw (window.Error? new Error(msg) : msg);
},
_obtainXmlReq: function(id, url) {
var p = url.match(new RegExp('^([a-z]+)://([^/]+)(.*)', 'i'));
if (p) {
if (p[2].toLowerCase() == document.location.hostname.toLowerCase()) {
url = p[3];
} else {
return null;
}
}
var req = null;
if (window.XMLHttpRequest) {
try { req = new XMLHttpRequest() } catch(e) {}
} else if (window.ActiveXObject) {
try { req = new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {}
if (!req) try { req = new ActiveXObject("Msxml2.XMLHTTP") } catch (e) {}
}
if (req) {
var th = this;
req.onreadystatechange = function() {
if (req.readyState == 4) {
req.onreadystatechange = th.dummy;
th.status = null;
try {
th.status = req.status;
th.responseText = req.responseText;
} catch (e) {}
if (!th.status) return;
var funcRequestBody = null;
try { eval('funcRequestBody = function() {\n' + th.responseText + '\n}') } catch (e) {}
funcRequestBody();
}
};
this._id = id;
}
return req;
},
_obtainScript: function(id, href) { with (document) {
var span = createElement('SPAN');
span.style.display = 'none';
body.insertBefore(span, body.lastChild);
span.innerHTML = 'Text for stupid IE.<s'+'cript></' + 'script>';
setTimeout(function() {
var s = span.getElementsByTagName('script')[0];
s.language = 'JavaScript';
if (s.setAttribute) s.setAttribute('src', href); else s.src = href;
}, 10);
this._id = id;
this._span = span;
}},
_obtainForm: function(id, url, method, queryText, queryElem) {
if (method == 'GET') {
queryText = url.split('?', 2)[1].split('&');
url = url.split('?', 2)[0];
}
var div = document.createElement('DIV');
var ifname = 'jshr_i_' + id;
div.id = 'jshr_d_' + id;
div.style.position = 'absolute'; div.style.visibility = 'hidden';
div.innerHTML =
'<form enctype="multipart/form-data"></form>' +
'<iframe src="javascript:\'\'" name="' + ifname + '" id="' + ifname + '" style="width:0px; height:0px; overflow:hidden; border:none"></iframe>'
var form = div.childNodes[0];
if (queryElem.length) {
form = queryElem[0].e;
if (form.tagName.toUpperCase() == 'FORM') {
queryElem = [];
} else {
form = queryElem[0].e.form;
for (var i = 0; i < queryElem.length; i++) {
var e = queryElem[i].e;
if (!e.form) {
return this._error('Element "' + e.name + '" does not belong to any form!');
}
if (e.form != form) {
return this._error('Element "' + e.name + '" belongs to different form. All elements must belong to the same form!');
}
}
}
var need = "multipart/form-data";
var given = form.attributes.encType || form.attributes.enctype || form.enctype;
if (given != need) {
return this._error('Attribute "enctype" of elements\' form must be "' + need + '" (for IE), "' + given + '" given.');
}
}
document.body.insertBefore(div, document.body.lastChild);
this._span = div;
var th = this;
setTimeout(function() {
for (var i = 0; i < queryText.length; i++) {
var pair = queryText[i].split('=', 2);
var e = document.createElement('INPUT');
e.type = 'hidden';
e.name = unescape(pair[0]);
e.value = pair[1] != null? unescape(pair[1]) : '';
form.appendChild(e);
}
for (var i = 0; i < queryElem.length; i++) {
var qe = queryElem[i];
qe.svName = qe.e.name;
qe.e.name = qe.name;
}
var sv = th._setAttributes(
form,
{
'action': url,
'method': method,
'onsubmit': null,
'target': ifname
}
);
form.submit();
th._setAttributes(form, sv);
for (var i = 0; i < queryText.length; i++) {
form.lastChild.parentNode.removeChild(form.lastChild);
}
for (var i = 0; i < queryElem.length; i++) {
queryElem[i].e.name = queryElem[i].svName;
}
}, 10);
},
_cleanupScript: function() {
var span = this._span;
if (span) {
this._span = null;
setTimeout(function() {
span.parentNode.removeChild(span);
}, 50);
}
if (this._id) {
PENDING[this._id] = false;
}
return false;
},
_hash2query: function(content, prefix, queryText, queryElem) {
if (prefix == null) prefix = "";
if (content instanceof Object) {
var formAdded = false;
for (var k in content) {
var v = content[k];
if (v instanceof Function) continue;
var curPrefix = prefix? prefix+'['+this.escape(k)+']' : this.escape(k);
if (this._isFormElement(v)) {
var tn = v.tagName.toUpperCase();
if (tn == 'INPUT' || tn == 'TEXTAREA' || tn == 'SELECT' || tn == 'FORM') {
if (tn == 'FORM') formAdded = true;
queryElem[queryElem.length] = { name: curPrefix, e: v };
} else {
return this._error('Invalid FORM element detected: name=' + (e.name||'') + ', tag=' + e.tagName);
}
} else if (v instanceof Object) {
this._hash2query(v, curPrefix, queryText, queryElem);
} else {
if (v === null) continue;
queryText[queryText.length] = curPrefix + "=" + this.escape('' + v);
}
if (formAdded && queryElem.length > 1) {
return this._error('If used, <form> must be single HTML element in the list.');
}
}
} else {
queryText[queryText.length] = content;
}
return true;
},
_isFormElement: function(e) {
return e && e.parentNode && e.parentNode.appendChild && e.tagName;
},
_getSid: function() {
var m = document.location.search.match(new RegExp('[&?]'+this.session_name+'=([^&?]*)'));
var sid = null;
if (m) {
sid = m[1];
} else {
var m = document.cookie.match(new RegExp('(;|^)\\s*'+this.session_name+'=([^;]*)'));
if (m) sid = m[2];
}
return sid;
},
_changeReadyState: function(s, reset) { with (this) {
if (reset) {
status = statusText = responseJS = null;
responseText = '';
}
readyState = s;
if (onreadystatechange) onreadystatechange();
}},
_setAttributes: function(e, attr) {
var sv = {};
var form = e;
if (e.mergeAttributes) {
var form = document.createElement('form');
form.mergeAttributes(e, false);
}
for (var k in attr) {
sv[k] = form.getAttribute(k);
form.setAttribute(k, attr[k]);
}
if (e.mergeAttributes) {
e.mergeAttributes(form, false);
}
return sv;
},
escape: function(s) {
return escape(s).replace(new RegExp('\\+','g'), '%2B');
}
}
})();