Una vez trabajado con el objeto XmlhttpsRequest en joomla, descubrimos que tiene un problema en su ejecución sobre Internet Explorer 8, cuando intentamos utilizar la función .responseXML, ya que, cuando generamos a través de un fichero.php el xml a pasar a nuestro sistema Ajax, descubrimos que siempre llega en formato texto.
Para descubrir que formato nos devuelve el objeto XmlhttpsRequest. Usaremos la siguiente función,XmlhttpsRequest.getAllResponseHeaders(), nos va a decir que el Content-type es siempre text/html, cuando debería decir que es text/xml. Esto es debido a que, cuando llamamos al generador de php, (fichero.php) aunque tengamos metida la cabecera, por otro lado imprescindible header('Content-type: text/xml'); tenemos que darnos cuenta que si ese fichero está registrado en el sistema, la tendencia de joomla será mostrar su contenido en la parte principal de la web, por tanto, aparte de contener el XML, contendrá lógicamente toda la información para mostrar la página (menús, plantilla, etc) y el fichero dejará de tener una sintaxis Xml correcta.
En firefox 3.6.8 descubrimos que no ocurre nada, y lee el fichero Xml a través de Dom sin problemas pero, la sorpresa llega con internet explorer 8, que no es capaz de leer nada. Esto es debido a que firefox 3.6.8 acepta una propiedad en su objeto XmlhttpsRequest, el cual le indicamos que reciba lo que reciba del servidor, lo interprete siempre como xml, y así lo hará aunque reciba un texto, si tiene sintaxis correcta de xml, lo sabrá interpretar. Esta propiedad es XmlhttpsRequest. overrideMimeType('text/xml'); donde le indicamos que siempre lo lea como text/xml. Esto soluciona el problema, para todos los navegadores que acepten esta propiedad. Pero ¿qué pasa con Internet Explorer que no la acepta?, es más, hemos saltado algo importante, si joomla devuelve la petición llena de código html para poder mostrar un index.htm correcto, ¿Cómo firefox es capaz de filtrar el código xml?, pues bien, aquí entra un interesantísimo parámetro de joomla, que es el format=raw en el enlace url que llamamos, esto lo que hace es solo devolver lo que el fichero al que llamamos produce, quitándole el reto de información de joomla, si ejecutamos una página joomla con raw, desaparecerán todos los marcos y menus, módulos etc, de la página. Es un formato “plano”. Un ejemplo será el siguiente https://www.misitiojoomla.es/index.php?option=com_articleinfo&format=raw, a este punto deducimos, no sin mucho esfuerzo que, para conseguir suplantar la propiedad overrideMimeType, bastaría con coger el texto que obtenemos con XmlhttpsRequest.resposeText, y transformarlo en xml. Pues bien, ¿Cómo es esto posible? Pues gracias a DOM Parser. Para no enredar más con el código voy a poner un ejemplo de 2 páginas .php donde se detalla con exactitud el uso tanto de XmlhttpsRequest, como el de Dom Parser. La idea es usar esta página como módulo joomla, funciona de la siguiente forma, primero hace una consulta sobre la base de datos y muestra 5 productos y un enlace, cuando el usuario hace un onmouseover, le aparecerá una ventana tipo pop-up con el título y la descripción del producto, sin recargar la página.
Mod_articleajax.php (Cliente que demanda conexión Ajax)
<?php /** * @version $Id: mod_articleajax.php 5203 2010-08-22 00:31:01z JesusN $ * @copyright Copyright (C) 2010 Jesús Manuel Nieto Carracedo.Todos los derechos reservados. * @package articleajax * Este módulo mostrará enlaces a 5 articulos actuales. * Cada enlace tiene un evento OnMouseOver para activarlo desde * com_articleinfo. */ ?> <?php //Vamos lo primero a incluir el fichero overlib_mini.js quien tendrá el código //necesario para poder crear la ventana. //Este desarrollo de ventana no es original Joomla, sino fue cedido por su creador //Erik Bosrup, hay versiones más recientes por si hicieran falta en //https://www.bosrup.com/web/overlib ?> <script type="text/javascript" src="/includes/js/overlib_mini.js"></script> <script type="text/javascript"> //Crear la variable request de XML var myRequest= false; function displayAjax(tempArticleID){ //Configurar URL de consulta de componente var myURL = 'index.php?option=com_articleinfo&format=raw&articlenum=' +tempArticleID; //Borrar myrequest myRequest =false; //Creamos myRequests que es un array con todos los objetos posibles. var myRequests = ["Microsoft.XMLhttps","Msxml2.XMLH TTP.5.0","Msxml2.XMLhttps","Msxml2.XMLhttps.4.0","Msxml2.XMLhttps.3.0"]; //Empezamos a bucleaar. for(var i=0 ; !myRequest && i<myRequests.length ; i++){ try{ myRequest = new ActiveXObject(myRequests[i]); // Internet Explorer } catch(e) { myRequest = false; } } if(!myRequest && typeof XMLhttpsRequest!='undefined') { myRequest = new XMLhttpsRequest(); // Firefox, Opera 8.0+, Safari.... if (myRequest.overrideMimeType){ myRequest.overrideMimeType('text/xml'); } } //Comprobar que el objeto Request es vál ido. if (!myRequest){ //Aquí ya usamos la ventana provista por Joomla. overlib('Error:No se pudo crear el objeto XMLhttpsRequest'); return False; } //Abrir solicitud de URL myRequest.open ('GET',myURL,true); //Enviar solicitud. myRequest.send(null); //Enlace para mostrar función n que se activa al devolver el resultado myRequest. //Importantísimo colocar dentro de la funciço n esta declaració n, sino no actualiza el //estado, al menos con mozilla firefox. myRequest.onreadystatechange = function(){ displayReturn(); } } function displayReturn(){ //Comprobar que el resultado se ha recibido, 4=completo if (myRequest.readyState==4 ){ //Comprobar el có digo de estado https if (myRequest.status==200){ //Comprobamos las cabeceras devueltas myRequest.getAllResponseHeaders(); if (!myRequest.overrideMimeType) { var texto = myRequest.responseText; if (window.DOMParser){ //Al no poder usar la propiedad OverRride, hay que usar DomPasser,el objeto NO es Internet Explorer parser=new DOMParser(); xmlDoc=parser.parseFromString(texto,"text/xml"); }else { // Internet Explorer 8 y anteriores xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async="false"; xmlDoc.loadXML(texto); } //Cargamos las variables var articleDom = xmlDoc.getElementsByTagName('article'); var mytitleDom = articleDom[0].getElementsByTagName('title')[0].firstChild.nodeValue; var mybodyDom = articleDom[0].getElementsByTagName('body')[0].firstChild.nodeValue; //Mostramos ventana con 2 segundos de duración overlib(mybodyDom,CAPTION,mytitleDom,BELOW,RIGHT,TIMEOUT,2000); } else { //Podremos usar la opció n nativa de responseXML. var article = myRequest.responseXML.getElementsByTagName('article'); myTitle = article[0].getElementsByTagName('title')[0].firstChild.nodeValue; myBody = article[0].getElementsByTagName('body')[0].firstChild.nodeValue; //Mostramos ventana con 2 segundos de duración . overlib(myBody,CAPTION,myTitle,BELOW,RIGHT,TIMEOUT,2000); } } else { //Si se produce algún error, lo mostramos con 5 segundos. //Le vamos a poner 2 segundos. El tiempo está en milisegundos. overlib('Hubo un problema con la respuesta (Request)', CAPTION,'Error Reportado',BELOW,RIGHT,TIMEOUT,2000); } } } </script> <small>M�dulo Ajax Activado</small><br/> <?php //Sin acceso directo defined('_JEXEC') or die('Acesso restringido'); //Definir variables locales. $db =&JFactory::getDBO(); $user =&JFactory::getUser(); $userID =(int) $user->get('id'); //Definir par�metros de fecha para garantizar que los artículos están disponibles $nullDate =$db->getNullDate(); $now =date('Y-m-d H:i:s',time()); //Crear una cadena de búsqueda para mostrar solamente artículos publicados $where ="a.state='1'". " AND (a.publish_up='".$nullDate."'". " OR a.publish_up<='".$now."')". " AND (a.publish_down='".$nullDate."'" . " OR a.publish_down>='".$now."')"; //Crear consulta $query ="SELECT a.id, a.title". " FROM #__content AS a". " WHERE ".$where."". " AND a.access <=".$userID.""; //Ejecutar la consulta para devolver un máximo de 5 registros $db->setQuery($query,0,5); if ($rows = $db->loadObjectList()){ //Procesar las filas de los artículos foreach($rows as $row) { //Procesar el título del artículo $artTitle=JText::_($row->title); //Crear evento mouseover para invocar la función displayAjax echo "<span onmouseover=displayAjax(".$row->id.");onmouseout=nd();>"; //Crear vínculo para el artículo actual. echo "<a href=index.php?option=com_content&view=article&id=". $row->id."&Itemid=44>".$artTitle."</a><br/></span>"; } } //Mostrar mensaje de error si falla la recuperación de la base de datos. echo $db->getErrorMsg(); ?>
articleinfo.php (Generador de php)
<?php /** * @version $Id: articleinfo.php 5203 2010-08-22 00:31:01z JesusN $ * @copyright Copyright (C) 2010 Jesús Manuel Nieto Carracedo.Todos los derechos reservados. * @package articleinfo * Este componente es un ejemplo de como funciona la tecnología AJAX, vamos a ampliar el * componente com_infoproductoAJAX para convertirlo en una "caja negra" de recuperación de * información. Este componente procesará el parámetro requerido articlenum para consultar * a la base de datos de aticulos y devolver el título y el texto del articulo en formato XML. */ //Sin acceso directo Joomla! defined('_JEXEC') or die('Acesso restringido'); //Obtener el ID de solicitud de la variable de cadena de consulta $articleNum = intval (JRequest::getVar ('articlenum')); //Definir valores predeterminados si la consulta falla $articleTittle = "Error titulo"; $articleBody = "Error Body"; //Obtener instancia del objeto de base de datos $db = &JFactory::getDBO(); //Creamos una consulta para devolver el id, titulo y texto del articulo. //Al colocar #__ delante de la tabla, joomla lo sustituye automáticamente //por el prefijo "jos_" que es el que corresponde. $query = "SELECT a.id, a.title, a.introtext". " FROM #__content AS a". " WHERE a.id=".$articleNum.""; $db->setQuery($query,0); //Ejecutar la consulta if ($rows = $db->loadObjectList()){ //Obtener primera fila devuelta, el cero es la primera posición $row = $rows[0]; //Carga el título y el texto del artículo en valores. $articleTittle = $row->title; $articleBody = $row->introtext; //Eliminar todo el HTML del texto del artículo $articleBody = strip_tags($articleBody); //Eliminar caracteres no alfanuméricos y de puntuación. //Me elimina los espacios asi que de momento esta funcionalidad la comento //$articleBody = preg_replace( //"/[^a-zA-Z0-9.?!$()\'\"]/","",$articleBody); //Si la longitud es mayor de 200, recortarla if (strlen ($articlebody)>200) { $articleBody = substr ($articleBody, 0,200); } } //Devolver XML del título y texto del artículo //Así generaríamos el xml //Ojo importantísimo es crear las cabeceras header, porque sin la primera //Internet Explorer 7 y 8 no serán capaces de encontrar la información ya //que no van a esperar a que se genere completamente el xml y dará error. header("Content-type: text/xml"); header("Cache-Control: no-cache, must-revalidate"); $cabecera='<?xml version="1.0" encoding="utf-8"?>'; //Posteriormente generamos el xml. //Imprescindible colocar la cabecera header para la correcta interpretación pero en joomla al tener que llamarlo dentro del //sistema nos obliga a usar el parámetro format=raw, lo que hace necesario hacer un DOM_parse. header('Content-type: text/xml'); echo "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"; echo " <article>\n"; echo " <title>".$articleTittle."</title>\n"; echo " <body>".$articleBody."</body>\n"; echo " </article>\n"; ?>