/******************************************************************************* * - AJAX Toolkit * * * * Esta API implementa la función 'ajaxSendRequest', que permite ejecutar re- * * motamente scripts en el servidor mediante peticiones originadas en el * * cliente. * * * * La función 'ajaxSendRequest' recibe como único argumento un objeto, que de- * * termina todos los aspectos configurables de la función. Un ejemplo válido * * de llamada es el siguiente: * * * * function myHandler(response, v1, v2, vn) * * { * * // ... * * } * * * * var opts = { * * method: 'get', * * url: '/scripts/js/php-ajax/script.php', * * queryVars: {name1: 'value1', name2: 'value2', nameN: 'valueN'}, * * responseType: 'text', * * handler: myHandler, * * handlerVars: [mivar1, mivar2, mivarn], * * async: true, * * showLoading: true, * * loadingBg: '#000000', * * loadingOp: 0.8, * * loadingImg: 'images/loading.gif', * * loadingImgW: 250, * * loadingImgH: 40, * * debug: true * * }; * * * * ajaxSendRequest(opts); * * * * A continuación se detallan cada una de las opciones: * * * * - method: El método que se utilizará en la llamada ('get' o 'post'). * * OPTIONAL. DEFAULT: 'get'. * * * * - url: La URL RELATIVA del script que se desea ejecutar en el * * servidor. Es importante que la URL sea relativa, ya que si * * se introduce con el dominio y el que introducimos cuando * * naveguemos por la página es diferente (poner www o no, por * * ejemplo) el objeto xmlhttp lo tomará como dominios dife- * * rentes y en algunos navegadores se bloqueará por seguri- * * dad. REQUIRED. * * * * - queryVars: Las variables que se van a pasar al script remoto. Las va- * * riables son un objeto de la forma {name1: 'value1', nameN: * * 'valueN'}. OPTIONAL. DEFAULT: null. * * * * - responseType: El tipo de respuesta que nos devolverá el servidor ('text',* * 'xml' o 'json'. El tipo de respuesta 'json' es similar al * * 'text', con la diferencia de que previamente a devolver la * * respuesta, ésta se evalúa. DEFAULT 'xml'. * * * * - handler: La función que manejará la respuesta. No el nombre de la * * función, sino una referencia a la misma. Dicha función de- * * berá estar definida por el usuario y deberá tener al menos * * un argumento, que será la respuesta. Si no se define nin- * * gún manejador y se está realizando una llamada síncrona, * * la llamada a la función 'ajaxSendRequest' devolverá la * * respuesta. OPTIONAL. DEFAULT: null. * * * * - handlerVars: Variables adicionales que se le pasarán al handler cuando * * se haya obtenido la respuesta. Las variables son un array * * de valores de la forma [mivar1, mivar2, mivarn]. OPTIONAL. * * DEFAULT: null. * * * * - async: Determina si se va a realizar una llamada síncrona (false) * * o asíncrona (true). * * * * En una llamada asíncrona con handler la función que llame * * a 'ajaxSendRequest' seguirá su ejecución tras la llamada y * * cuando la respuesta esté lista, se le pasará al handler. * * * * En una llamada asíncrona sin handler la función sigue y * * nadie maneja la respuesta. * * * * En una llamada síncrona con handler la función que realiza * * la llamada se espera hasta tener la respuesta y se la pasa * * al handler. * * * * En una llamada síncrona sin handler la funcíon se espera y * * cuando termina la llamada, 'ajaxSendRequest' devuelve la * * respuesta. OPTIONAL. DEFAULT: true. * * * * - showLoading: Indica si se debe mostrar un div bloqueante indicando que * * se está esperando la respuesta. OPTIONAL. DEFAULT: false. * * * * - loadingBg: Color de fondo del div bloqueante de la forma #RRGGBB. * * OPTIONAL. DEFAULT: #ffffff. * * * * - loadingOp: Opacity del div bloqueante. Real de 0 a 1. OPTIONAL. DE- * * FAULT: 0.4. * * * * - loadingImg: Ruta relativa de la imagen que se mostrará en el loading. * * OPTIONAL. DEFAULT: img/ajax-loader.gif. * * * * - loadingImgW: Anchura de la imagen que se mostrará en el loading. Sirve * * para poder centrar la imagen en el div. OPTIONAL. DEFAULT: * * 100. * * * * - loadingImgH: Altura de la imagen que se mostrará en el loading. Sirve * * para poder centrar la imagen en el div. OPTIONAL. DEFAULT: * * 100. * * * * - debug: Indica si se deben mostrar o no los mensajes de error. * * OPTIONAL. DEFAULT: false. * * * * @date 2008/01/11 * * @version 0.4 * * @author Antonio Vilar Sánchez * *******************************************************************************/ /** * Determina si un objeto es de tipo array */ function isArray(object) { return object.constructor == Array; } /** * Crea el objeto xmlhttp */ function ajaxCreateObject() { var xmlhttp; try { xmlhttp = new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) { try { xmlhttp = new ActiveXObject('Microsoft.XMLHTTP'); } catch(f) { xmlhttp = null; } } if (!xmlhttp && typeof XMLHttpRequest != 'undefined') { xmlhttp = new XMLHttpRequest(); } return xmlhttp; } /** * Chequea las opciones */ function ajaxCheckParams(opts) { var errorMsg = ''; if (typeof opts.method == 'undefined') { opts.method = 'GET'; // default value } else { opts.method = opts.method.toUpperCase(); if (opts.method != 'GET' && opts.method != 'POST') { errorMsg = '* method must be GET or POST\n'; } } if (typeof opts.url == 'undefined') { errorMsg += '* url cannot be empty\n'; } if (typeof opts.responseType == 'undefined') { opts.responseType = 'XML'; // default value } else { opts.responseType = opts.responseType.toUpperCase(); if (opts.responseType != 'TEXT' && opts.responseType != 'XML' && opts.responseType != 'JSON') { errorMsg = '* responseType must be TEXT, XML or JSON\n'; } } if (typeof opts.async == 'undefined') { opts.async = true; // default value } else if (typeof opts.async != 'boolean') { errorMsg += '* async must be boolean\n'; } if (typeof opts.handler != 'undefined' && typeof opts.handler != 'function') { errorMsg += '* handler must be a function\n'; } else if (typeof opts.handler == 'undefined' && opts.async) { opts.responseType = 'TEXT'; } if (typeof opts.handlerVars != 'undefined' && !isArray(opts.handlerVars)) { errorMsg += '* handlerVars must be an array\n'; } if (typeof opts.debug == 'undefined') { opts.debug = false; // default value } else if (typeof opts.debug != 'boolean') { opts.debug = true; errorMsg += '* debug must be boolean\n'; } if (typeof opts.showLoading == 'undefined') { opts.showLoading = false; // default value } else if (typeof opts.showLoading != 'boolean') { errorMsg += '* showLoading must be boolean\n'; } if (typeof opts.loadingBg == 'undefined') { opts.loadingBg = '#ffffff'; // default value } else { var re_hexcolor = /^#[0-9a-fA-F]{6}$/; if (!re_hexcolor.test(opts.loadingBg)) { errorMsg += '* loadingBg must be the form #RRGGBB\n'; } } if (typeof opts.loadingOp == 'undefined') { opts.loadingOp = 0.4; // default value } else if (typeof opts.loadingOp != 'number' || opts.loadingOp < 0 || opts.loadingOp > 1) { errorMsg += '* loadingOp must be a number between 0 and 1\n'; } if (typeof opts.loadingImgW == 'undefined') { opts.loadingImgW = 100; // default value } else if (typeof opts.loadingImgW != 'number') { errorMsg += '* loadingImgW must be a number\n'; } if (typeof opts.loadingImgH == 'undefined') { opts.loadingImgH = 100; // default value } else if (typeof opts.loadingImgH != 'number') { errorMsg += '* loadingImgH must be a number\n'; } if (errorMsg && opts.debug) { alert('ERROR:\n\n' + errorMsg); return false; } return true; } /** * Obtiene la respuesta del objeto xmlhttp */ function ajaxGetResponse(opts, xmlhttp) { if (opts.responseType == 'XML') { response = xmlhttp.responseXML; } else { response = xmlhttp.responseText; } if (opts.responseType == 'JSON') { response = eval(response); } return response; } /** * Pasa la respuesta al manejador */ function ajaxCallHandler(opts, response) { if (typeof opts.handlerVars == 'object') { // manejador con argumentos adicionales handlerArgs = ''; for (var i = 0; i < opts.handlerVars.length; i++) { handlerArgs += 'opts.handlerVars[' + i + '], '; } handlerArgs = handlerArgs.replace(/, $/, ''); eval("opts.handler(response, " + handlerArgs + ")"); } else { opts.handler(response); } } /** * Muestra imagen de loading */ function ajaxCreateLoading(opts) { if (opts.showLoading) { var blockerDiv = document.createElement('div'); blockerDiv.id = 'ajaxBlockerDiv'; blockerDiv.style.position = 'fixed'; blockerDiv.style.zIndex = '3000'; blockerDiv.style.width = '100%'; blockerDiv.style.height = '100%'; blockerDiv.style.top = '0px'; blockerDiv.style.left = '0px'; blockerDiv.style.background = opts.loadingBg; blockerDiv.style.opacity = opts.loadingOp; blockerDiv.style.filter = 'alpha(opacity=' + opts.loadingOp * 100 + ')'; document.body.appendChild(blockerDiv); var loadingImg = document.createElement('img'); if (typeof opts.loadingImg == 'undefined') { // Obtenemos la URL del script ajax.js var scripts = document.getElementsByTagName('script'); for (var i = 0; i < scripts.length; i++) { if (scripts[i].src.search(/\/ajax.js$/) != -1) { baseURL = scripts[i].src.replace('ajax.js', ''); } } loadingImg.src = baseURL + 'img/ajax-loader.gif'; } else { loadingImg.src = opts.loadingImg; } loadingImg.border = '0'; loadingImg.style.position = 'absolute'; loadingImg.style.top = '50%'; loadingImg.style.left = '50%'; loadingImg.style.marginTop = '-' + opts.loadingImgH / 2 + 'px'; loadingImg.style.marginLeft = '-' + opts.loadingImgW / 2 + 'px'; blockerDiv.appendChild(loadingImg) document.body.appendChild(blockerDiv); } } /** * Elimina la imagen de loading */ function ajaxDestroyLoading(opts) { if (opts.showLoading) { document.body.removeChild(document.getElementById('ajaxBlockerDiv')); } } /** * Muestra la excepcion si está activado el debug */ function ajaxShowException(opts, e) { if (opts.debug) { alert(e); } } /** * Función pricipal */ function ajaxSendRequest(opts) { if (!ajaxCheckParams(opts)) { return false; } var xmlhttp, uri, vars, data, response, requestArgs, handlerArgs; xmlhttp = ajaxCreateObject(); if (typeof opts.queryVars == 'object') { vars = '?'; for (var varName in opts.queryVars) { vars += varName + '=' + opts.queryVars[varName] + '&'; } vars = vars.replace(/&$/, ''); } else { vars = ''; } if (opts.method == 'GET') { uri = opts.url + vars; data = null; } else { uri = opts.url; data = vars.replace(/^\?/, ''); } try { xmlhttp.open(opts.method, uri, opts.async); if (opts.responseType == 'XML') { xmlhttp.overrideMimeType('text/xml'); } if (opts.method == 'POST') { xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); } if (opts.async == false) { // Síncrono ajaxCreateLoading(opts); xmlhttp.send(data); response = ajaxGetResponse(opts, xmlhttp); if (typeof opts.handler == 'function') { ajaxCallHandler(opts, response); ajaxDestroyLoading(opts); } else { ajaxDestroyLoading(opts); return response; } } else { // Asíncrono xmlhttp.onreadystatechange = function() { try { if (xmlhttp.readyState == 4) { try { if (xmlhttp.status == 200) { if (typeof opts.handler == 'function') { ajaxCallHandler(opts, ajaxGetResponse(opts, xmlhttp)); } ajaxDestroyLoading(opts); } } catch(e) {} } } catch(e) { ajaxShowException(opts, e); } } ajaxCreateLoading(opts); xmlhttp.send(data); } } catch(e) { ajaxShowException(opts, e); } }