/**
* Library for AJAX.
*
* @package AJAX
* @author Livesport, s.r.o.
* @copyright (c) 2008 Livesport, s.r.o.; {@link http://www.livesport.cz/}
* @since 2007/09/22
*/
/**
* Constrructor of XHR object.
*
* @constructor
*/
function XHR()
{
// init the object
this._init();
// create AJAX
this.createAJAX()
};
/**
* Create the XHR object and set up it.
*
* @return {XHR} Returns a fluent interface.
*/
XHR.prototype.createAJAX = function()
{
try {
this.xhr = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e1) {
try {
this.xhr = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e2) {
this.xhr = null;
}
}
if (! this.xhr) {
if (typeof XMLHttpRequest != 'undefined') {
this.xhr = new XMLHttpRequest();
} else {
this.failed = true;
}
}
return this;
};
/**
* Set a variable to append URL.
*
* @param {String} name Name of variable.
* @param {Mixed} value Variable value.
* @return {XHR} Returns a fluent interface.
*/
XHR.prototype.setVar = function(name, value) {
this.vars[name] = new Array(value, false);
return this;
};
/**
* Run the AJAX request.
*
* @param {String} ajaxContent Content for AJAX request.
* @param {Boolean} xml Send as XML (optional, default is false)?
*/
XHR.prototype.runAjax = function(ajaxContent, xml)
{
if (this.failed) {
this.onFail();
} else {
xml = (cJsLib.empty(xml) || xml == false) ? false : true;
// check if content type is not a XML string
(!xml) ? this._createUrl(ajaxContent) : this.urlString = ajaxContent;
if (this.element) {
this.elementObj = document.getElementById(this.element);
}
if (this.xhr) {
var self = this;
if (this.method == 'GET') {
completeUrlString = this.requestFile + this.queryStringSeparator + this.urlString;
this.xhr.open(this.method, completeUrlString, true);
} else {
this.xhr.open(this.method, this.requestFile, true);
try {
this.xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
} catch (e) {}
}
this.xhr.onreadystatechange = function() {
switch (self.xhr.readyState) {
// not catchable in Safari, Konqueror, Opera
case 1:
self.onLoading();
break;
case 2:
self.onLoaded();
break;
case 3:
self.onInteractive();
break;
case 4:
self.response = self.xhr.responseText;
self.responseXML = self.xhr.responseXML;
self.responseStatus[0] = self.xhr.status;
self.responseStatus[1] = self.xhr.statusText;
// execute user defined function?
if (self.execute) {
self.runAfterResponse();
}
// append AJAX response to defined element
if (self.elementObj) {
elemNodeName = self.elementObj.nodeName;
nodeName = elemNodeName.toLowerCase();
if (nodeName == 'input' || nodeName == 'select' || nodeName == 'option' || nodeName == 'textarea') {
self.elementObj.value = self.response;
} else {
self.elementObj.innerHTML = self.response;
}
}
if (self.responseStatus[0] == '200') {
self.onCompletion(self.responseXML, self.response);
} else {
self.onError();
}
self.userRedirect();
self.urlString = '';
break;
}
};
this.xhr.send(this.urlString);
}
}
};
/**
* Adjust overlay layer to a new layer.
*
* @return {XHR} Returns a fluent interface.
*/
XHR.prototype.placeOverlay = function()
{
if (cJsLib.$('overlay') == null) {
pDimension = cJsLib.getDocSize();
args = new Object();
args.id = 'overlay';
args.style = 'visibility:hidden;';
mOverlay = cJsLib.createElement('div', args);
document.body.appendChild(mOverlay);
cJsLib.setStyle(mOverlay, 'width:' + pDimension.width.toString() + 'px;height:' + pDimension.height.toString() + 'px;');
delete mOverlay, pDimension;
}
return this;
};
/**
* Adjust overlay message container with AJAX pre-loader
*
* @param {Integer} ajaxIndex Index of AJAX object which is parent for closing action.
* @param {String} preloadMessage Message for pre-loader.
* @return {XHR} Returns a fluent interface.
*/
XHR.prototype.placePreLoader = function(ajaxIndex, preloadMessage, asDom)
{
if (!cJsLib.isNull(ajaxIndex) && cJsLib.$('overlay-container') == null) {
asDom = cJsLib.isNull(asDom) || ! asDom ? false : true;
// main container for message
args = new Object();
args.id = 'overlay-container';
container = cJsLib.createElement('div', args);
// message container for AJAX results
args = new Object();
args.id = 'overlay-message';
overlayMessage = cJsLib.createElement('div', args);
// AJAX preloader message
preLoader = cJsLib.createElement('span', {'id': 'preloader'});
if (! asDom) {
preLoader.appendChild(document.createTextNode(preloadMessage));
} else {
preLoader.appendChild(preloadMessage);
}
overlayMessage.appendChild(preLoader);
// overlay message closer
args = new Object();
args.id = 'overlay-closer';
args.onclick = 'ajaxObject[' + ajaxIndex + '].destroyOverlay();';
args.title = 'Klikněte pro zavření popup okna.';
closer = cJsLib.createElement('a', args);
container.appendChild(overlayMessage);
container.appendChild(closer);
container.style.visibility = 'hidden';
document.body.appendChild(container);
cJsLib.center(container);
container.style.visibility = 'visible';
delete container, overlayMessage, overlayMessage, preLoader;
}
return this;
};
/**
* Clear the AJAX pre-loader image and replace with empty DIV.
*
* @return {XHR} Returns a fluent interface.
*/
XHR.prototype.clearAjaxPreLoader = function()
{
var toReplace = cJsLib.$('overlay-message');
var pElement = toReplace.parentNode;
var newReplace = document.createElement('div');
newReplace.setAttribute('id', 'overlay-message');
newReplace.appendChild(document.createTextNode(''));
pElement.replaceChild(newReplace, toReplace);
return this;
};
/**
* Destroy the overlay layer.
*
* @return {XHR} Returns a fluent interface.
*/
XHR.prototype.destroyOverlay = function()
{
cJsLib.destroyObj('overlay-container');
cJsLib.destroyObj('overlay');
return this;
};
/**
* Set a new AJAX request type method.
*
* @param {GET|POST} methodType A new value of request method
* @return {XHR} Returns a fluent interface.
*/
XHR.prototype.setMethod = function(methodType)
{
this.method = ! cJsLib.empty(methodType) && methodType.toUpperCase() == 'POST' ? 'POST' : 'GET';
return this;
};
/**
* Get a method type of AJAX request.
*
* @return {POST|GET}
*/
XHR.prototype.getMethod = function()
{
return this.method;
};
/**
* Set a request filename for processing AJAX script on server.
*
* @param {String} fileName Filename.
* @return {XHR} Returns a fluent interface.
*/
XHR.prototype.setRequestFile = function(fileName)
{
if (! cJsLib.empty(fileName)) {
this.requestFile = fileName;
}
return this;
};
/**
* Enable / disable execute function `runAfterResponse()` after successfuly XHR request.
*
* Note: Default setting is after successfully response execute function `runAfterResponse()`
* which call function `clearAjaxPreLoader()`.
*
* @param {Boolean} stat A new flag value.
* @return {XHR} Returns a fluent interface.
*/
XHR.prototype.setExecuteAfterRun = function(stat)
{
this.execute = ! cJsLib.isNull(stat) || stat === true ? true : false;
return this;
};
/**
* Reset object (return all properties to default value.
*
* @return {XHR} Returns a fluent interface.
*/
XHR.prototype.reset = function()
{
this._resetFunctions;
return this;
};
// Private methods
/**
* Initize the AJAX object.
*/
XHR.prototype._init = function()
{
this.failed = false;
// sending method of request
this.method = 'POST';
// URI separator
this.queryStringSeparator = '?';
// separator for arguments in URL
this.argumentSeparator = '&';
// URL
this.urlString = '';
// enable / disable encoding of URI strigns
this.encodeUri = true;
// requested AJAX script on server
this.requestFile = '';
// after AJAX finished execute function `runAfterResponse()`?
this.execute = true;
// ID of element for showing AJAX result
// class may display result to defined element via method `innerHTML`
// or setting value (for input, select, option, textarea)
this.element = null;
// DOM object of element for showing AJAX result
this.elementObj = null;
// array with URL parameters
this.vars = new Object();
// array with AJAX response code and response message
this.responseStatus = new Array(2);
// use overlayed DIV above all content
this.useOverlay = false;
// URL for user redirection
this.userRedirectUrl = null;
// reset all functions
this._resetFunctions();
};
/**
* Reset all function - set to default.
*/
XHR.prototype._resetFunctions = function()
{
// AJAX readyState with value 1, is not catchable in Opera (9.25, 9.5b), Konqueror, Safari
this.onLoading = function() {};
// on slow internet connestion is better place (show) overlay layer with a AJAX pre-loader
// run manually after execute the action which initize the AJAX, i.e. after click
// to button for example
if (this.useOverlay == true) {
// if enabled using overlay, show overlayed layer with the AJAX result message container
this.onLoaded = function() { this.placeOverlay(); };
// after AJAX finished, remove a pre-loader and clean the AJAX result message container
this.runAfterResponse = function() { this.clearAjaxPreLoader(); };
} else {
this.onLoaded = function() {};
this.runAfterResponse = function() {};
}
// funtion for redirecting after AJAX finishing
this.userRedirect = function() {};
this.onInteractive = function() {};
this.onCompletion = function() {};
this.onError = function() {};
this.onFail = function() {};
};
/**
* Encode a variable.
*/
XHR.prototype._encodeVar = function(name, value, returnVars) {
if (returnVars == true) {
return Array(encodeURIComponent(name), encodeURIComponent(value));
} else {
this.vars[encodeURIComponent(name)] = Array(encodeURIComponent(value), true);
}
}
/**
* Process the URL.
*
* @param {String}
* @param {Boolean} encode Encode a URL?
*/
XHR.prototype._processUrl = function(string, encode)
{
encoded = encodeURIComponent(this.argumentSeparator);
regexp = new RegExp(this.argumentSeparator + "|" + encoded);
varArray = string.split(regexp);
for (var i = 0; i < varArray.length; i++) {
urlVars = varArray[i].split('=');
if (encode == true){
this._encodeVar(urlVars[0], urlVars[1]);
} else {
this.setVar(urlVars[0], urlVars[1]);
}
}
};
/**
* Create the URL address from string.
*
* @param {String} urlString URL string.
*/
XHR.prototype._createUrl = function(urlString)
{
if (this.encodeUri && this.urlString.length) {
this._processUrl(this.urlString, true);
}
if (urlString) {
if (this.urlString.length) {
this.urlString += this.argumentSeparator + urlString;
} else {
this.urlString = urlString;
}
}
// prevents caching of URL
this.setVar("random_var", new Date().getTime());
tmpUrl = new Array();
for (key in this.vars) {
if (this.vars[key][1] == false && this.encodeUri == true) {
encoded = this._encodeVar(key, this.vars[key][0], true);
delete this.vars[key];
this.vars[encoded[0]] = Array(encoded[1], true);
key = encoded[0];
}
tmpUrl[tmpUrl.length] = key + "=" + this.vars[key][0];
}
if (urlString) {
this.urlString += this.argumentSeparator + tmpUrl.join(this.argumentSeparator);
} else {
this.urlString += tmpUrl.join(this.argumentSeparator);
}
};
// END: Private methods