/** * 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