Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Evandro Oliveira

Objeto AJAX inteligente

Recommended Posts

Salve iMasters.

 

Bom, trago hoje uma criação que pode ajudar em muito que está começando no mundo AJAX.

 

Vejo por aí que muitos de vocês fazem uso de jQuery APENAS para utilização de AJAX. Os frameworks estão aí, vieram pra ficar, são uma mão-na-roda e ajudam muito!!! Desde que você saiba o que está fazendo! Muita gente baixa as bibliotecas, enche o sistema de plug-ins e, quando vai ter que dar manutenção, se perde todo na quantidade de informações de terceiros agregadas ao sistema!

 

Para projetos de grande porte, existe ainda outro problema: custo de dados. Incorporar todos os 25Kb (55 se o seu servidor não suportar gzip) por causa de um recurso é coisa de amador! Os 155Kb da biblioteca descomprimida então, nem pensar!!

 

O objeto XMLHttpRequest é uma standard, prevista pela W3C que pode, E DEVE ser utilizado de forma independente.

 

O grande problema é que, devido à disparidade entre os navegadores (e vocês pensando que isso só acontecia com CSS), alguns métodos e eventos previstos para um - navegador - pode não estar presente em outro(s).

 

O Objeto AJAX inteligente surge para preencher esta lacuna entre um objeto XMLHttp cru e uma framework inteira subutilizada.

 

Conteúdo obsoleto foi escondido

 

Sem mais blá-blá-blá, a definição:

 

/**
 * Creates an Ajax Class.
 * @author Evandro Oliveira <evandrofranco[at]gmail[dot]com>
 * @version 0.2.3 [2010-09-10 11:34 GMT-0300]
 * 
 * @param {Callback} noAjax A function to be run if XMLHttp object cannot
 * 	be created.
 * 
 * @return a new Ajax object
 */
var Ajax = function(noAjax){
	// Verifying XMLHttp support
	if(!window.XMLHttpRequest) return noAjax();
	else {
		var xhr = new XMLHttpRequest();
		if(xhr == null) return noAjax();
	}
	
	// Config database
	var params = new Object();
	params.url = 'about:blank';
	params.method = 'GET';
	params.async = true;
	params.timeout = 30000;
	params.response = false;
	params.onabort = function(){};
	params.oncomplete = function(){};
	params.onerror = function(){};
	params.ontimeout = function(){};
	params.onupdate = function(){};
	params.headers = new Array();
	
	/**
	 * This function defines a new URL to be run with Ajax object.
	 * @param {String} newUrl The new URL to run.
	 * @return Itself.
	 */
	this.setUrl = function(newUrl){ 
		if(newUrl != undefined) params.url = newUrl;
		return this;
	};
	
	/**
	 * This function defines the request method.
	 * @param {String} newMethod The new request method.
	 * @return Itself.
	 */
	this.setMethod = function(newMethod) { 
		if(newMethod != undefined) params.method = newMethod;
		return this;
	};
	
	/**
	 * This function defines whether the request'll be asynchronous.
	 * @param {Boolean} value The async switch.
	 * @return Itself;
	 */
	this.setSync = function(value) {
		if(value != undefined) params.async = (value != false);
		return this;
	};
	
	/**
	 * Defines the max execution time for each request.
	 * 	This function was originallly created for MSIE8 and
	 * 	this Ajax object emulates the behavior in all major
	 * 	browsers.
	 * @param {Number} newTimeout The max execution time in miliseconds.
	 */
	this.setTimeout = function(newTimeout) {
		if(newTimeout != undefined) params.timeout = newTimeout;
		return this;
	};
	
	/**
	 * Defines the return mode.
	 * 	Switch between XML data (true) or Text data (false).
	 * @param {Boolean} mode The response mode.
	 * 	To get an XML response, set it to true. False swith
	 * 	gets a pure-text response.
	 * @return Itself.
	 */
	this.setXmlReturn = function(mode) {
		if(mode != undefined) params.response = (mode != false);
		return this;
	};
	
	/**
	 * Adds events listener callbacks. Actions to be executed
	 * 	at [Abort, Complete, Error, Update and Timeout] cases.
	 * @param {String} event The case listener.
	 * @param {Callback} callback The action to be taken.
	 */
	this.setEvent = function(event, callback){
		switch(event){
			case 'complete': params.oncomplete = callback; break;
			case 'timeout': params.ontimeout = callback; break;
			case 'update': params.onupdate = callback; break;
			case 'abort': params.onabort = callback; break;
			case 'error': params.onerror = callback; break;
		}
	};
	
	/**
	 * Adds or edit the headers table.
	 * @param {String} name The header name.
	 * @param {String} value The header value.
	 */
	this.setHeader = function(name, value){
		if(name == undefined || value == undefined) return;
		for (var i = 0, ln = params.headers.length; i < ln; i++) 
			if (params.headers[i].name = name) {
				params.headers[i].value = value;
				return;
			}
		var newHeader = new Object();
		newHeader.name = name;
		newHeader.value = value;
		params.headers.push(newHeader);
	};
	
	/**
	 * Adds access to the XMLHttp.abort() method. Also calls
	 * 	the abort event listener callback.
	 */
	this.abort = function(){
		xhr.abort();
		params.onabort();
	};
	
	/**
	 * Starts the request.
	 * 	- Prepare the XMLHttp object
	 *  - Set the headers
	 *  - Set the listeners
	 *  - Prepare data
	 *  - Send data
	 *  - Call respective listeners
	 * @param {Object} data The data to be send.
	 */
	this.send = function(data){
		var newData = new Array();
		for(var i in data) newData.push(i + '=' + data[i]);
		data = newData.join('&');
		if(params.method == 'GET') params.url += '?' + data;
		
		xhr.open(params.method, params.url, params.async);
		xhr.onreadystatechange = function(){
			params.onupdate(xhr.readyState);
			if(xhr.readyState == 4){
				clearTimeout(myTimeout);
				if(xhr.status == 200)
					params.oncomplete((params.response)? xhr.responseXML : xhr.responseText);
				else params.onerror(xhr.status, xhr.statusText);
			}
		};
		for(var i = 0, ln = params.headers.length; i < ln; i++)
			xhr.setRequestHeader(params.headers[i].name, params.headers[i].value);
		xhr.send(data);
		var myTimeout = setTimeout(function(){
			xhr.abort();
			params.ontimeout();
		}, params.timeout);
	};
	
	this.setHeader('content-type', 'application/x-www-form-urlencoded');
	this.setHeader('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest');
};

 

 

Trata-se de uma classe (orientação a objetos).

 

Para descrição de métodos e utilização, citarei exemplos conseguintes, unindo-os, ao final, temos um sistema em funcionamento.

 

Primeiro, criamos a página que recebe as requisições:

ajax.txt

requisição ajax funcionou!

Agora vamos criar um novo objeto da classe Ajax

var xmlhttp = new Ajax();

O método construtor nos permite passar à classe, em forma de parâmetro, uma função (callback) que será executada caso não seja possível criar um novo objeto AJAX.

 

Podemos, por exemplo, enviar um alerta ao usuário

var xmlhttp = new Ajax(function(){ alert('Não foi possível criar o objeto AJAX!') });
Teste no IE6 ;)

 

Como somos programadores inteligentes, vamos utilizar isso a nosso favor, vamos definir uma variável global que nos indica se temos ou não suporte a AJAX.

var hasAjax = true;
var xmlhttp = new Ajax(function(){ hasAjax = false; });

if(!hasAjax) alert('Ajax indisponível');

Pronto! Temos uma criação segura do objeto e ainda temos como verificar se existe ou não suporte à tecnologia. Vamos agora, configurar o objeto.

 

Em objetos XMLHttpRequest padrão, temos o método open() para definir o método de transação de dados, a url a ser acessada e se o acesso será ou não assíncrono.

 

Para o objeto Ajax, temos métodos em separado para cada atributo.

 

método

xmlhttp.setMethod('GET');
O método get já é definido por padrão, não sendo necessário fazer essa atribuição.

 

url

xmlhttp.setUrl('http://forum.imasters.com.br');

sincronia

xmlhttp.setSync(true);
Atenção: Este método define se a requisição será assíncrona, o que pode causar uma certa confusão na hora de definir o seu valor. Por padrão, o valor é dado como true o que indica que o usuário continuará livre para navegar enquanto a requisição XMLHttp estiver sendo processada (comportamento padrão).

 

Algumas novas propriedades são adicionadas ao objeto Ajax. São elas: XmlReturn e Timeout

 

xmlReturn define se o valor retornado pelo objeto Ajax ao concluir a requisição será em formato xml ou texto.

xmlhttp.setXmlReturn(false);
True: retorna em XML. False(padrão): Retorna em texto.

 

timeout define o tempo que o objeto deverá aguardar até o término da requisição (em milisegundos).

xmlhttp.setTimeout(10000);
Aguardando 10 segundos...

Nota: Se o tempo de timeout do objeto Ajax for maior que o tempo de timeout do servidor, o objeto Ajax encerrará com o evento onerror enviando como parâmetro o código de erro 504 - Gateway Time Out.

 

Após isso, é necessário definir o comportamento do controlador em determinados eventos. Por exemplo, para descobrir se a requisição está terminada, no objeto XMLHttp, temos que verificar no evento readystatechange o status do objeto. Tudo isso é gerenciado pelo objeto Ajax, cabendo ao desenvolvedor apenas atrelar as funções a cada um dos seguintes eventos:

 

abortagem - quando a requisição é cancelada antes de se completar e antes do timeout expirar.

xmlhttp.setEvent('abort', function(){});
Este callback não recebe parâmetros.

 

atualização - cada vez que o objeto XMLHttp muda de estado

xmlhttp.setEvent('update', function(){});
Por padrão, o callback recebe o valor da propriedade readyState do objeto XMLHttp.

 

conclusão - ao terminar a requisição com sucesso

xmlhttp.setEvent('complete', function(){});
Os dados passados por parâmetro ao callback é a resposta xmlhttp.responseText ou xmlhttp.responseXml conforme definido pelo método xmlhttp.setXmlReturn.

 

erro - ao terminar a requisição sem sucesso

xmlhttp.setEvent('error', function(){});
Este callback recebe dois parâmetros:

- O código de erro HTTP

- A descrição do erro

 

tempo esgotado - quando se expira o timeout do objeto Ajax.

xmlhttp.setEvent('timeout', function(){});
Este callback não recebe parâmetros.

 

Brinde! Cabeçalhos:

Podemos enviar junto com a requisição, cabeçalhos que indicam o tipo de requisição que estamos fazendo e que tipo de dados esperamos de volta

xmlhttp.setHeader('content-type', 'application/x-www-form-urlencoded');

Pronto! Nosso objeto Ajax está configurado e pronto para rodar. Mas como rodamos?

Através do método send(), como no objeto XMLHttp, com uma nova facilidade: Independente do método de requisição, os dados de envio podem ser passados como parâmetro para send() em forma de objeto. A conversão será transparente e funcional.

 

Método antigo

xmlhttp.open('GET', 'pagina.php?nome=Evandro&idade=21');

Novo método

xmlhttp.setUrl('pagina.php');
xmlhttp.send({nome: "Evandro"; idade: 21;});

Para terminar, para a galera que já está acostumada com jQuery, é possível configurar vários parâmetros ao mesmo tempo de uma vez:

xmlhttp.setMethod('GET').setUrl('pagina.php').setSync(true);

Lembra do nosso arquivo ajax.txt lá do começo? Bom então agora vamos juntar todas as informações que aprendemos e criar um sistema de MOTD(Message of the day - mensagem do dia) para o nosso site!

 

HTML - criando um contêiner para o MOTD

<div id="motd"></div>

 

Javascript

var hasAjax = true;

var xhr = new Ajax(function(){ hasAjax = false; });

if(hasAjax) {
    xhr.setUrl('ajax.txt').setEvent('complete', function(message){
        document.getElementById('motd').innerHTML = message;
    }).setEvent('update', function(){
        document.getElementById('motd').innerHTML = 'Aguarde, recuperando mensagem...';
    }).send();
}

 

 

Link para a documentação mais atual

 

Bônus Lá no começo, disse que poderia testar o que acontece caso não haja suporte a AJAX no IE6. Mas você pode querer que este fadado navegador também funcione com o seu sistema, sei lá os seus motivos. Para isso, basta criar a classe XMLHttpRequest

 

/**
 * Adds the standard XMLHttpRequest class to IE6.
 * @author Evandro Oliveira <evandrofranco[at]gmail[dot]com>
 * 
 * @version 0.1 [2010-09-10 10:37 GMT-0300]
 * 
 * @return A new XMLHTTP object if supported, else NULL.
 */
if(!window.XMLHttpRequest) var XMLHttpRequest = function(){
	var tryes = new Array("MSXML2.XMLHTTP.7.0", "MSXML2.XMLHTTP.6.0", "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP");
	var XMLHttp = null;
	while(XMLHttp == null && tryes.length > 0)
		try { XMLHttp = new ActiveXObject(tryes.shift()); }
		catch(e){};
	return XMLHttp;
}

 

Vale lembrar que este suporte deve ser carregado ANTES de instanciar um novo objeto Ajax.

 

ajax.js

ajax-min.js

(Links atualizados)

 

Suporte ao IE 6

ie6ajax.js

ie6ajax-min.js

 

Aguardo dúvidas, feedback e opiniões. Espero que gostem!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Documentação obsoleta foi escondida.

 

Resumão dos métodos e aplicações

- setUrl( String newUrl );

 

Define a URL a ser carregada pelo objeto Ajax.

 

newUrl : A nova URL.

- setMethod( String newMethod = 'GET' );

 

Define o método de requisição.

 

newMethod : O novo método. Lembrando que não existem apenas GET e POST; e que XMLHttp trabalha muito bem com REST e SOAP.

- setSync( Boolean asynchronous = TRUE );

 

Define se a requisição será assíncrona.

 

asynchronous : O valor da sincronia. True não bloqueia o navegador enquanto a requisição estiver em andamento. False sim.

- setHeader( String name, String value );

 

Adiciona ou edita cabeçalhos do controlador.

 

name : O nome do cabeçalho. Caso o cabeçalho já exista, será sobreposto.

value : O valor do cabeçalho informado.

- setXmlReturn( Boolean xmlReturn = FALSE );

 

Define se o valor retornado caso a requisição seja completa será a reposta em XML ou texto plano.

 

xmlReturn : O valor de retorno da requisição. True retorna uma resposta XML, false uma resposta em texto plano.

- setTimeout( Number timeout = 30000 );

 

Define o tempo máximo que o objeto Ajax deve aguardar antes de disparar o evento ontimeout.

 

timeout : O tempo de espera em milisegundos (1s E-3).

- setEvent( String event, Function callback );

 

Amarra uma função ao evento mencionado.

 

event : O nome do evento, que pode ser:

  • Abort - Ao chamar o método .abort() durante uma requisição.
  • Complete - Ao terminar uma requisição com sucesso e o código HTTP 200.
  • Error - Ao terminar uma requisição obtendo um código HTTP inesperado.
  • Update - A cada vez que o objeto XMLHttp muda de estado. É equivalente a configurar a propriedade onreadystatechange.
  • Timeout - Ao expirar o tempo definido pelo método setTimeout().

callback : O conjunto de instruções a serem realizadas em cada evento. Vale notar que alguns eventos em específico retornam valores como parâmetro sendo:

  • Complete - Envia a resposta do objeto XMLHttp conforme definido em setXmlResponse().
  • Error - Envia o código de erro HTTP e seu valor "amigável".
  • Update - Envia o readyState do objeto XMLHttp.

- send( Object data );

 

Inicia a requisição e envia os dados passados como parâmetro.

 

data : Os dados que serão enviados durante a requisição.

- abort();

 

Aborta a requisição.

Nota: Este método só deve ser chamado durante a requisição, caso contrário ocasionará erro no script impedindo a execução dos comandos seguintes.

 

 

Link para a documentação mais atual

Compartilhar este post


Link para o post
Compartilhar em outros sites

Boa essa daí...

Um dia senti vontade de brincar com isso também, dar uma 'automatizada' no Ajax e saiu o 'pai' disso aqui.

 

Bacaninha seu objeto, mas algumas coisinhas são 'anti-práticas'... Claro que já dá uma boa reduzida no volume de código, mas se prestar bem atenção vai ver que pode diminuir ainda mais.

Que fique bem claro: NÃO É UMA CRÍTICA, E SIM UMA DICA.

 

A minha idéia é a mesma, mas a sintaxe é um pouco mais 'direta', na versão atual:

var ajax = new myAjax();
ajax.post(url, data, callback);

var ajax = new myAjax();
ajax.get(url, data, elemento_container, callback);

Minha classe já tá na versão 4.1 [o link é para a versão 4.0] e mudei váaaarias coisas até a versão 4.0, tanto que foi meio assim: 1.0 -> 2.0 -> 3.0 -> 4.0.

Agora que a coisa já tá estável o suficiente, as modificações são poucas, então vou 'desacelerando' as versões.

 

É isso ae!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Rick, bacana sua iniciativa e me parece que a sua ideia está bem mais madura que a minha. Infelizmente é impossível não fazer comparações entre as ferramentas mas, talvez por causa disso, é possível encontrar algumas diferenças nas linhas de pensamento.

 

Primeiro de tudo o objetivo. Seu projeto visa automatizar a transação AJAX tornando o mais rápido possível a aplicação da ferramenta.

Meu projeto visa integrar métodos ausentes (abort() -> ie6@msxml1) e exclusivos (timeout -> ie8) em um novo objeto que visa minimizar o máximo possível as diferenças entre navegadores.

 

Coisas que eu aproveitaria da sua idéia na minha: A possibilidade de enviar todos os valores para os métodos setHeader e setEvent, ao invés de fazer um a um.

 

Não se acanhe em criticar com o objetivo de agregar conhecimento/qualidade. Não fosse o João Batista me "criticar" aqui, com toda certeza eu não teria evoluído sequer metade do que considero que evolui neste 10 meses de participação no iM.

 

Aproveitando o ensejo das "críticas construtivas", gostaria de apontar coisas que eu não faria, presentes no seu projeto:

 

- Notação simplificada e direta:

a = ['um', 'dois', 'três'];
b = { um : 1, dois : 2, tres : 3 };

Quando se trata de uma ferramenta disponibilizada para uso público, você deve se atentar muito ao crossbrowsing. Este tipo de notação é problemático e incompleto em navegadores antigos (e mobiles). Se o desenvolvedor quiser utilizar, que use, mas não é a sua ferramenta que vai ocasionar o erro de script.

 

var a = new Array('um','dois','três');
var b = new Object();
b.um = 1; b.dois = 2; b.tres = 3;

- Globalização de ações:

A flexibilidade do Javascript às vezes nos faz esquecer que a mesma é uma linguagem orientada a objetos (alguns sequer sabem). Então, fazer com que um objeto AJAX faça a impressão dos dados é similar a ter um objeto DAO fazendo o print em formato de tabelas. O máximo que o seu objeto de requisição de servidor deve oferecer são os dados processados, a fim de serem tratados através de outro objeto. Não entendeu? Procure no source do jQuery o método load(), que tem funcionalidade semelhante ao ápice da sua ferramenta, e verá que cada ação é separada na sua devida camada. A requisição é efetuada pelo objeto de requisição, o processamento pelo setor de processamento e a saída pelo setor de saída. Como diz minha namorada: "cada um no seu quadrado".

 

- JSON vs EVAL:

JSON não é e nunca foi javascript puro!!! Utilizar eval para tratar a resposta como informações JSON é perigoso! Existe um protótipo de domínio público, pronto para ser utilizado, direto do site oficial que implementa a funcionalidade de modo crossbrowser e seguro.

 

 

(function (s) {
  // This prototype has been released into the Public Domain, 2007-03-20
  // Original Authorship: Douglas Crockford
  // Originating Website: http://www.JSON.org
  // Originating URL    : http://www.JSON.org/JSON.js

  // Augment String.prototype. We do this in an immediate anonymous function to
  // avoid defining global variables.

  // m is a table of character substitutions.

  var m = {
    '\b': '\\b',
    '\t': '\\t',
    '\n': '\\n',
    '\f': '\\f',
    '\r': '\\r',
    '"' : '\\"',
    '\\': '\\\\'
  };

  s.parseJSON = function (filter) {

    // Parsing happens in three stages. In the first stage, we run the text against
    // a regular expression which looks for non-JSON characters. We are especially
    // concerned with '()' and 'new' because they can cause invocation, and '='
    // because it can cause mutation. But just to be safe, we will reject all
    // unexpected characters.

    try {
      if (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.
        test(this)) {

          // In the second stage we use the eval function to compile the text into a
          // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
          // in JavaScript: it can begin a block or an object literal. We wrap the text
          // in parens to eliminate the ambiguity.

          var j = eval('(' + this + ')');

          // In the optional third stage, we recursively walk the new structure, passing
          // each name/value pair to a filter function for possible transformation.

          if (typeof filter === 'function') {

            function walk(k, v) {
              if (v && typeof v === 'object') {
                for (var i in v) {
                  if (v.hasOwnProperty(i)) {
                    v[i] = walk(i, v[i]);
                  }
                }
              }
              return filter(k, v);
            }

            j = walk('', j);
          }
          return j;
        }
      } catch (e) {

      // Fall through if the regexp test fails.

      }
      throw new SyntaxError("parseJSON");
    };
  }
) (String.prototype);

 

 

- AJAX não é só GET e POST:

Seu objeto ainda emite um erro, dizendo que o tipo de requisição é inválido. Quem deve validar ou não a requisição é o servidor. Novamente está misturando as camadas, como acontece na resposta dos erros HTTP. Você não precisa definir uma tabela com os erros e seus respectivos valores. Esta tabela já está definida! Basta devolver os dados através das propriedades XMLHttpRequest.status e XMLHttpRequest.statusText

 

 

- Uso da Exceção e Erro:

Esta eu achei uma super sacada digna de elogio. Enviar uma resposta ao depurador contendo informações sobre como solucionar o problema é excelente!! Mas você abusa dessa funcionalidade ao utilizá-la caso não haja suporte a AJAX. Enviar um ERRO causa a parada crítica do processamento javascript. Isso quer dizer que se o navegador não suportar AJAX ele não vai executar mais nada que vier depois disso, mesmo que não sejam funções dependentes de AJAX.

 

Espero que sirva de ajuda, quem sabe nossos projetos não se cruzam mais pra frente numa única ferramenta útil e poderosa?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Documentação obsoleta foi escondida

 

Versão 3.9

 

Changelog

/*
Métodos removidos:
 - setUrl
 - setMethod
 - setSync
 - setXmlReturn
 - setTimeout

Novos métodos adicionados:
 - setParam

Correções:
 * Corrigida a falha que não enviava de volta o objeto, causando erros na chamada de métodos em estilo jQuery.
 * Corrigida a falha crítica que parava a execução do script se o método abort() fosse chamado fora de uma requisição.
 * Corrigida a falha que não enviava cabeçalhos, exceto com o método GET.
 * Corrigida a falha que não fazia checagem correta de headers, gerando duplicidade.

Modificações:
 * O objeto agora tem um nome SmartAjax.
 * Comentários e documentação no código em português.
 * A concepção do código agora é dividida em 4 setores: Parâmetros, Eventos, Cabeçalhos e Execução. O que facilita o estudo da implementação.
 * Os métodos de acesso agora recebem, tanto modificações individuais quanto conjuntas (Agradecimentos ao Henrique Barcelos).
 * Modo de operação do método setHeader: Definir o valor do header como 'NULL' exclui o header. Chamar o método sem argumentos exclui todos os headers.
 * O Callback do evento "complete" agora retorna o objeto XMLHttpRequest utilizado na requisição, tornando possível ler os cabeçalhos de resposta do servidor, acessar informações da requisição e decidir sobre o uso de texto ou XML sem a necessidade de definir um parâmetro.
 * Em caso de erros não previstos, o callback do evento "error" enviará um terceiro parâmetro, o objeto Exception, que permite fazer o rastreamento de cada chamada que gerou o erro.

[3.8]
 * Adequação da documentação ao formato de 76 Colunas
 * Funcionalidade que impede o depurador de gerar um erro até que o método send() seja acionado, em casos onde não há suporte ao objeto XMLHttpRequest.
 * Funcionalidade que permite que o objeto seja instanciado passando como argumentos, valores iniciais de parâmetros, eventos e cabeçalhos.

[3.9]
 * Corrigida falha que impedia que fossem passados um evento e um parâmetro de timeout diretamente na criação do objeto.
*/

- constructor( Function noAjax[, Object configsObject[, HeadersObject]] );

Método construtor. A chamada SmartAjax.constructor() não existe por si só. Ela é feita apenas durante a instância de um novo objeto.

Argumentos:

  • Function noAjax: Um callback de saída chamado caso não seja possível criar uma instância de XMLHttpRequest.
  • Object configsObject: Um mapa de valores que define os valores iniciais dos parâmetros e eventos. Como existe a ambiguidade da palavra-chave "timeout", para definir seu valor e seu callback na criação do objeto, faz-se necessário envolver os parâmetros ou eventos em um objeto chamado 'params' ou 'events' respectivamente (ver exemplos).
  • Object headersObject: Mapa de valores dos cabeçalhos semelhante à definição de cabeçalhos do método setHeaders().

Exemplos:

// Alertando o usuário que não possui um navegador com suporte a AJAX
var ajax = new SmartAjax(function(){ alert('Seu navegador não possui suporte a AJAX') });

// Definindo a URL padrão como a página de busca do google
var ajax = new SmartAjax(function(){}, { 'url':'http://google.com/search' });

// Definindo valores iniciais para o evento timeout
var ajax = new SmartAjax(function(){}, { 'params': { 'timeout': 20000 }, 'events': { 'timeout': function(){ alert('tempo esgotado!'); } });

// Definindo um cabeçalho inicial
var ajax = new SmartAjax(function(){}, {}, {'content-type': 'text/plain'});

- setParam( String name, String value );

- setParam( Object params );

 

Altera os parâmetros do objeto SmartAjax. Pode receber apenas um parâmetro no primeiro formato, ou vários parâmetros em um objeto, no segundo formato.

Parâmetros:

  • URI url: A página a ser requisitada.
  • String method [GET]: O método de requisição (o objeto funciona perfeitamente com POST, GET, REST e SOAP).
  • Boolean async [TRUE]: Se a requisição será assíncrona ou se deverá bloquear o uso do navegador enquanto estiver em execução.
  • Number timeout [30000]: Tempo de espera da requisição em milissegundos. Deve ser menor que o timeout definido no servidor, caso contrário o objeto retornará o erro 504 ao invés de chamar o callback de timeout.

Exemplos

// Definindo de maneira única a propriedade URL
SmartAjax.setParam('url','http://forum.imasters.com.br');

// Definindo as propriedades METHOD e TIMEOUT
SmartAjax.setParam({'method' : 'post', 'timeout' : 20000});

- setEvent( String event, Function callback );

- setEvent( Object events );

 

Atrela uma função a um determinado evento. Pode receber apenas uma função vinculada a um único evento ou receber um objeto contendo o mapa evento=callback.

Eventos:

  • Function abort: Bloco de código a ser executado ao se cancelar uma requisição.
  • Function complete: Comandos realizados na completude da requisição.
  • Function error: Instruções realizadas caso um erro seja detectado.
  • Function timeout: Aguarda a requisição até o tempo definido pelo parâmetro timeout. Caso o tempo se esgote, chama esta função.
  • Function update: Realiza esta chamada cada vez que a propriedade readyState do objeto XmlHttpRequest mudar.

Exemplos

// Definição direta do evento ABORT, passando diretamente uma função como parâmetro de callback.
SmartAjax.setEvent('abort', function(){alert('requisição cancelada');});

// Criando uma função que será utilizada de callback para o evento TIMEOUT
function timeout(){alert('tempo esgotado!');}

// Definição dos callbacks para os eventos COMPLETE e TIMEOUT.
// Veja que em COMPLETE, passamos uma função que recebe um argumento, o objeto XMLHttpRequest.
// Veja, também, que para TIMEOUT, apenas informamos o nome da função de callback (sem os parênteses).
SmartAjax.setEvent({'complete': function(xhr){alert(xhr.responseText);}, 'timeout': timeout});

- setHeader( String name, String value );

- setHeader( Object headerList );

 

Modifica a tabela de cabeçalhos adicionando novos ou editando os existentes. Recebe um único cabeçalho em dois parâmetros 'nome' e 'valor' ou um mapa no formato nome=valor. Caso o valor do header seja do tipo NULL, o header será excluído. Se o método for chamado sem argumentos, a tabela de headers será esvaziada.

 

Exemplos

// Definição direta do cabeçalho CONTENT-TYPE
SmartAjax.setHeader('content-type', 'text/plain');

// Definição de dois cabeçalhos ao mesmo tempo
SmartAjax.setHeader({'content-type':'text/plain','accept':'text/plain'});

// Definição de um cabeçalho enquanto exclui-se outro
SmartAjax.setHeader({'content-type':'text/plain','HTTP_X_REQUESTED_WITH':null});

// Exclusão direta de apenas um cabeçalho. Note que é
//     necessário enviar NULL para o segundo parâmetro.
//     Caso contrário, o cabeçalho será criado/alterado
//     com o valor em branco ''
SmartAjax.setHeader('HTTP_X_REQUESTED_WITH', null);

// Exclusão de todos os cabeçalhos
SmartAjax.setHeader();

- abort();

 

Cancela uma requisição em andamento e, após isso, chama o callback definido em ABORT.

 

Exemplo

// Definição do callback para o evento ABORT
SmartAjax.setEvent('abort', function(){alert('requisição cancelada');});

// Chamada
SmartAjax.abort();

- send( Object data );

 

Prepara o objeto XMLHttpRequest, configura, envia cabeçalhos, define os eventos, processa os dados e efetua a requisição. Inicia a escuta dos eventos e chama os callbacks correspondentes.

 

Exemplo

// Configuramos o callback que será lançado ao concluir a requisição
SmartAjax.setEvent('complete',function(xhr){alert(xhr.responseText);});

// Enviamos dados pela requisição
SmartAjax.send({'nome':'Evandro','idade':22);

Definição

 

/**
 * Definição da classe SmartAjax
 * @author Evandro Oliveira <evandrofranco[at]gmail[dot]com>
 * @version 0.3.9 [2010-09-29 09:23 GMT-0300]
 * @license (cc) by-nd http://creativecommons.org/licenses/by-nd/3.0/
 * @link http://evandrofranco.com.br/lib/js/ajax.js
 * 
 * @param {Callback} noAjax Função que será lançada caso não haja suporte a
 * 	AJAX.
 * 
 * @param {Object} configObject Mapa de valores de configuração inicial.
 * 	Semelhante às chamadas de setParam e setEvent quando passados objetos
 * 	como argumentos. Se o valor da propriedade for uma função, esta será
 * 	definida como um evento. Caso contrário, será definida como parâmetro.
 * 	@see setParam.
 * 	@see setEvent.
 * 
 * @param {Object} headersObject Mapa de valores de cabeçalhos iniciais.
 * 	Sua definição resulta em várias chamadas do método setHeader passando
 * 	como argumentos, cada item deste objeto.
 * 	@see setHeader.
 * 
 * @return {SmartAjax} Uma nova instância de objeto SmartAjax.
 */
var SmartAjax = function(noAjax, configObject, headersObject){
	/**
	 * Para fins de fluência de script, o objeto é criado e só gera erros
	 * 	caso não possua uma definição para o método send()
	 */
	this.setParam = function(){
		return this;
	};
	this.setEvent = function(){
		return this;
	};
	this.setHeader = function(){
		return this;
	};
	this.abort = function(){
	};
	this.send = function(){
		throw new Error('Sem suporte para o objeto XMLHttpRequest');
	};
	
	/**
	 * Verificação de suporte. Caso não seja possível criar o objeto,
	 * 	devolvemos um objeto com todos os métodos definidos e um gerador de
	 * 	erros no método send().
	 */
	try {
		var xhr = new XMLHttpRequest();
	} 
	catch (e) {
		if (typeof(noAjax) == 'function') 
			noAjax();
		return this;
	}
	
	/**
	 * Daqui pra frente, admitimos que há suporte ao objeto XMLHttpRequest.
	 */
	// Definição da classe 'param'
	var param = function(name, value){
		var type = new Object();
		if (typeof(value) != typeof(params[name])) 
			return this.name = name;
		this.value = value;
		this.isParam = true;
		return this;
	};
	
	/**
	 * Objeto Params.
	 * Utilizado para armazenar os valores necessários para utilização do
	 * 	objeto SmartAjax.
	 */
	var params = new Object();
	params.url = 'about:blank';
	params.method = 'get';
	params.async = true;
	params.timeout = 30000;
	
	/**
	 * Modifica parâmetros do objeto SmartAjax.
	 * Pode receber duas strings contendo o nome e valor do parâmetro ou
	 * 	pode receber um objeto no formato nome=valor
	 *
	 * @param {String} name O nome do parâmetro.
	 * @param {String} value O novo valor do parâmetro.
	 *
	 * @param {Object} Um objeto contendo as propriedades do parâmetro a
	 * 	serem alteradas.
	 *
	 * @return SmartAjax.
	 */
	this.setParam = function(name, value){
		var defParam = function(param){
			if (param.isParam) 
				params[param.name] = param.value;
		}
		if (typeof(name) == 'string') 
			defParam(new param(name, value));
		else 
			if (typeof(name) == 'object') 
				for (var i in name) 
					defParam(new param(i, name[i]));
		return this;
	};
	
	/* Definição da classe event */
	var event = function(event, callback){
		if (events[event] == undefined || typeof(callback) != 'function') 
			return;
		this.event = event;
		this.callback = callback;
		this.isEvent = true;
		return this;
	};
	
	/**
	 * Objeto Events.
	 * Armazena funções que serão lançadas em ocorrências específicas do
	 * 	objeto SmartAjax.
	 */
	var events = new Object();
	events.abort = function(){
	};
	events.complete = function(){
	};
	events.error = function(){
	};
	events.timeout = function(){
	};
	events.update = function(){
	};
	
	
	/**
	 * Amarra uma função a um determinado evento.
	 * Cada função receberá diferentes parâmetros em sua respectiva
	 * 	chamada.
	 * Pode receber uma string como nome da função e a função como segundo
	 * 	parâmetro ou pode receber um objeto que mapeia cada evento como
	 * 	nome da propriedade e a função como valor da mesma.
	 *
	 * @param {String} event O evento lançador da função.
	 * @param {Function} callback A função a ser executada.
	 *
	 * @param {Object} event Objeto contendo como nome da propriedade, o
	 * 	evento especificado e o valor da propriedade deve ser a função a
	 * 	ser executada.
	 *
	 * @return SmartAjax.
	 */
	this.setEvent = function(eventName, callback){
		var defEvent = function(evt){
			if (evt.isEvent) 
				events[evt.event] = evt.callback;
		}
		if (typeof(eventName) == 'string') 
			defEvent(new event(eventName, callback));
		else 
			if (typeof(eventName) == 'object') 
				for (var i in eventName) 
					defEvent(new event(i, eventName[i]));
		return this;
	};
	
	/* Definição da classe header */
	var header = function(name, value){
		if (typeof(name) != 'string') 
			return;
		if (value == null) 
			return headers.clear(name);
		this.name = name;
		this.value = value;
		this.isHeader = true;
		return this;
	};
	
	/**
	 * Objeto headers.
	 * Armazena os cabeçalhos a serem enviado ao objeto SmartAjax antes do
	 * 	início da requisição.
	 */
	var headers = new Array();
	headers.push = function(){
		var headerExists = function(headerName){
			for (var i = 0, ln = headers.length; i < ln; i++) 
				if (headers[i].name.toLowerCase() == headerName.toLowerCase()) 
					return i;
			return false;
		}
		for (var i = 0, ln = arguments.length; i < ln; i++) 
			if (arguments[i].isHeader) {
				var header = new Object();
				header.name = arguments[i].name;
				header.value = arguments[i].value;
				var j = headerExists(header.name);
				j = (j === false) ? headers.length : j;
				headers[j] = header;
			}
	};
	headers.clear = function(headerName){
		if (headerName == undefined) 
			while (this.length) 
				this.pop();
		else 
			if (typeof(headerName) == 'string') 
				for (var i = 0, ln = this.length; i < ln; i++) 
					if (this[i].name.toLowerCase() == headerName.toLowerCase()) {
						this.splice(i, 1);
						return;
					}
	};
	
	/**
	 * Altera a tabela de cabeçalhos adicionando novos valores ou
	 * 	modificando valores existentes.
	 * Pode receber duas strings contendo o nome e valor do cabeçalho ou
	 * 	pode conter uma matriz desses valores para fins de modificação
	 * 	múltipla.
	 *
	 * @param {String} name O nome do cabeçalho.
	 * @param {String} value O valor do respectivo cabeçalho.
	 *
	 * @param {Object} headerList Um mapa de nome=valor dos headers a serem
	 * 	adicionados/modificados na tabela. Definir 'NULL' como valor do
	 * 	header envia uma requisição de exclusão do mesmo.
	 *
	 * @return SmartAjax.
	 */
	this.setHeader = function(name, value){
		if (arguments.length == 0) 
			return headers.clear();
		if (typeof(name) == 'string') 
			headers.push(new header(name, value));
		if (typeof(name) == 'object') 
			for (var i in name) 
				headers.push(new header(i, name[i]));
		return this;
	};
	
	/**
	 * Adiciona a funcionalidade abort() aos objetos AJAX que não o tenham.
	 * Também é utilizada para lançar o evento abort.
	 *
	 * @return SmartAjax.
	 */
	this.abort = function(){
		try {
			xhr.abort();
		} 
		catch (e) {
		};
		events.abort();
		return this;
	};
	
	/**
	 * Inicia a requisição
	 * 	- Prepara o objeto AJAX.
	 *  - Define os cabeçalhos.
	 *  - Amarra os eventos.
	 *  - Prepara os dados.
	 *  - Envia os dados.
	 *  - Chama os eventos respectivos.
	 *
	 * @param {Object} data Os dados a serem enviados.
	 *
	 * @return SmartAjax.
	 */
	this.send = function(data){
		var newData = new Array();
		for (var i in data) 
			newData.push(i + '=' + data[i]);
		data = newData.join('&');
		if (params.method.toUpperCase() == 'GET') 
			params.url += '?' + data;
		xhr.open(params.method, params.url, params.async);
		xhr.onreadystatechange = function(){
			events.update(xhr.readyState);
			if (xhr.readyState == 4) {
				clearTimeout(myTimeout);
				if (xhr.status == 200) {
					events.complete(xhr);
				}
				else 
					events.error(xhr.status, xhr.statusText);
			}
		};
		for (var i = 0, ln = headers.length; i < ln; i++) 
			xhr.setRequestHeader(headers[i].name, headers[i].value);
		try {
			xhr.send(data);
			var myTimeout = setTimeout(function(){
				try {
					xhr.abort();
				} 
				catch (e) {
				};
				events.timeout();
			}, params.timeout);
		} 
		catch (error) {
			events.error(error.code, error.message, error);
		};
			};
	
	if (typeof(configObject) == 'object') 
		for (var i in configObject) {
			if (typeof(configObject[i]) == 'function') 
				this.setEvent(i, configObject[i]);
			else 
				if (i == 'events') 
					this.setEvent(configObject[i]);
				else 
					if (i == 'params') 
						this.setparam(configObject[i]);
					else 
						this.setParam(i, configObject[i]);
		}
	
	if (typeof(headersObject) == 'object') 
		for (var i in headersObject) 
			this.setHeader(i, headersObject[i]);
	
	this.setHeader('content-type', 'application/x-www-form-urlencoded');
	this.setHeader('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest');
	
	return this;
};

 

 

Download:

smartAjax.js

smartAjax-min.js

 

Atenção!

Não utilize os links diretos! Faça o download, hospede em seu servidor para utilização. A ferramenta está em constante atualização e pode provocar erros no seu sistema se for utilizado o source original.

 

Link para a documentação mais atual

 

 

Bônus: "plugin" que transforma formulários em elementos SmartAjax.

Definição:

/**
 * Transforma formulários em elementos SmartAjax. Necessário a utilização
 * 	da ferramenta SmartAjax, disponível em
 * 	@see http://evandrofranco.com.br/lib/js/smartAjax.js
 * 
 * @author Evandro Oliveira <evandrofranco[at]gmail[dot]com>
 * 
 * @version 0.1.2 [2010-09-28 08:45 GMT-0300]
 * 
 * @license (cc) by-nd http://creativecommons.org/licenses/by-nd/3.0/
 * 
 * @link http://evandrofranco.com.br/lib/js/smartAjaxForm.js
 * 
 * @param {SmartAjax} smartAjaxObject Controlador Ajax responsável pela
 * 	requisição
 * 
 * @return Em caso de sucesso, retorna um {Boolean}FALSE para impedir o
 * 	envio tradicional do formulário. Em caso de falha, retorna {NULL} e
 * 	não afeta as funcionalidades ou propriedades do formulário.
 */
function makeAjaxForm(form, ajax){
	try {
		if (typeof(ajax.send) !== 'function' ||
		form.submit == undefined ||
		!(ajax instanceof SmartAjax)) 
			return;
	} 
	catch (e) {
		return;
	}
	
	var act = new String((form.action == '')? document.location : form.action);
	var qry = act.indexOf('?');
	if(qry != -1) act = act.substring(0, (qry - 1));
	var method = (form.method == '')? 'GET' : form.method;
	var enctype = (form.enctype == '')? 'application/x-www-form-urlencoded' : form.enctype;
	
	ajax.setParam({
		'method':method,
		'url':act.valueOf()
	}).setHeader('content-type', enctype);

	form.onsubmit = function(){
		var items = this.getElementsByTagName('input');
		var data = new Object();
		
		for (var i = 0, ln = items.length; i < ln; i++)
			data[items.item(i).name] = items.item(i).value;	
	
		ajax.send(data);
		return false;
	}
}

 

 

Nota: A versão 1.2 é compatível com Internet Explorer (6-9);

 

Exemplo de uso:

html

<form action="logar.php" method="post" id="login">
   <p>Usuario: <input type="text" name="nome"></p>
   <p>Senha: <input type="password" name="senha"></p>
   <button type="submit">Login!</button>
</form>
<div id="resultado">Você ainda não tentou um login</div>

 

Logar.php

<?php if(empty($_POST['nome'])) die('Campo "nome" não foi preenchido!');

$usuarios = array(
   'Evandro' => 'iMasters',
   'Visitante' => 'visitante',
   'root' => ''
);

if(!in_array($_POST['nome'], array_keys($usuarios))) die('Usuário não existe!');

if($_POST['senha'] != $usuarios[$_POST['nome']]) die('Senha incorreta');

echo 'Sucesso! Você está logado. Seja bem vindo, '. $_POST['nome'];

 

javascript

window.onload = function(){
    var ajax = new SmartAjax();

    var atualizaResultado = function(resposta){
        document.getElementById('resultado').innerHTML = resposta.responseText;
    }

    ajax.setEvent('complete', atualizaResultado);

    makeSmartAjaxForm(document.getElementById('login'), ajax);
}

 

smartAjaxForm.js[1.6Kb]

smartAjaxForm-min.js[895b]

Compartilhar este post


Link para o post
Compartilhar em outros sites

Versão 0.4.2

 

Changelog

 

/*
Correções:
 * Corrigida da falha crítica que não modificava os parâmetros do objeto.
 * Corrigida a falha que causava mal-funcionamento em requisições síncronas.

Modificações:
 * Alteração no modo de funcionamento do método construtor.
 * Alteração no modo de uso do callback noAjax.
 * Alteração no comportamento padrão do objeto SmartAjax.
 * Alteração na funcionalidade do método setHeader.
 * Incorporação da compatibilidade com IE6- e outros navegadores.
 * Adicionada funcionalidade de requisições autenticadas (usuário e senha).
 * Redução da quantidade de código (26% para a versão completa e 22% para a versão minificada).
 * Aumento expressivo de performance (ganhos de até 63% no GoogleChrome).
 * Redução do consumo de memória.

[0.4.1]
 * Corrigida falha ao passar uma String como parâmetro do método send().

[0.4.2]
 * Corrigido erro de digitação no bloco de compatibilidade.
*/

* Alteração de funcionamento do método construtor

 

- constructor( [Object params[, Object events[, Object headers]]] );

Método construtor. A chamada SmartAjax.constructor() não existe por si só. Ela é feita apenas durante a instância de um novo objeto.

Argumentos:

  • Mapa de parâmetros idêntico ao que seria passado para o método setParams();
  • Mapa de eventos contendo o nome do evento e um callback;
  • Conjunto de cabeçalhos a serem definidos. Se o valor do cabeçalho for igual a 'NULL', este será descartado.

Exemplo:

var ajax = new SmartAjax({'url':'google.com/search'}, {'complete':function(xhr){alert(xhr.responseText);}}, {'content-language':'pt-br'});

* Alteração no modo de uso do callback 'noAjax'

O callback 'noAjax' continua servindo para executar instruções caso não seja possível iniciar uma requisição através do objeto XMLHttpRequest. Porém, a partir da versão 0.4, sua definição deve ser feita como um evento, através do método setEvent, com o identificador 'noAjax'. Este valor inicial lança um erro que será exibido no console indicando que não há suporte a requisições XMLHttp. Substituindo o callback, o erro será substituído pelo novo bloco de instruções recebido.

Exemplo:

ajax.setEvent('noAjax', function(){ alert('Seu navegador não dá suporte a requisições AJAX'); });

* Alteração no comportamento padrão do objeto SmartAjax

Por padrão, até a versão 0.3.9, toda requisição feita através do método send() em navegadores sem suporte a requisições XMLHttp geravam um erro crítico, obrigando o programador a envolver as chamadas do método send() em blocos try-catch. Com a nova implementação do evento 'noAjax', não é mais necessário tratar ou checar se há suporte ou não do navegador para requisições XMLHttp. Basta programar normalmente para navegadores complacentes com os padrões e indicar os blocos de exceção no callback 'noAjax'. Quando um erro é encontrado, seja na resposta do servidor ou no funcionamento do objeto SmartAjax, o evento 'error' é disparado enviando como único parâmetro, um objeto de classe Error, informando a causa da falha.

 

* Alteração na funcionalidade do método setHeader

Qualquer valor para o cabeçalho enviado que não seja do tipo String acarretará na exclusão do cabeçalho.

 

* Incorporação da compatibilidade com IE6- e outros navegadores

Até a versão 0.3.9, a compatibilidade com IE6 e inferiores se dava através de um pequeno plug-in, mas ainda deixava carentes de assistência, os navegadores mais limitados. A partir da versão 0.4, não é mais necessário o plug-in e há o suporte a navegadores que não disponibilizem o objeto XMLHttpRequest. Dessa forma, chamar métodos como open() e setRequestHeader() não ocasionam mais erros. A falta de suporte ficou concentrada no evento 'noAjax'. Todo tratamento de navegadores deficientes deve ser feito dentro do respectivo callback.

 

* Adicionada a funcionalidade de requisições autenticadas

É possível passar dois novos parâmetros ao objeto SmartAjax: 'username' e 'password'. Dessa forma é possível fazer requisições em domínios que possibilitem autenticação HTTP e via URI.

Exemplo:

var ajax = new SmartAjax({'url':'restrito.php','username':'root','password':''});

* Redução da quantidade de código

A nova versão completa possui 7109bytes. Isso corresponde a 26% menos custo de dados do que a versão anterior. A versão reduzida (sem comentários e indentação) é 25% menor, enquanto a versão minificada (linha única, variáveis curtas) é 22% menor. São apenas 50 linhas de código para estudo.

 

* Aumento expressivo de performance

* Redução do consumo de memória

Testes de perfil (Criando 10000 instâncias do objeto SmartAjax).

Perfis feitos com Mozilla Firefox 4 beta 5 + FirebugAddon e Google Chrome 7.051 beta.

 

Versão 0.3.9

 

Firefox

Imagem Postada

 

Chrome

Imagem Postada

 

 

Versão 0.4

 

Firefox

Imagem Postada

 

Chrome

Imagem Postada

 

 

No Google Chrome, foi possível observar uma melhora de até 63% na performance, além do consumo de memória muito inferior.

 

 

Documentação Atualizada.

 

- constructor( [Object params[, Object events[, Object headers]]] );

Método construtor. A chamada SmartAjax.constructor() não existe por si só. Ela é feita apenas durante a instância de um novo objeto.

Argumentos:

  • Mapa de parâmetros idêntico ao que seria passado para o método setParams();
  • Mapa de eventos contendo o nome do evento e um callback;
  • Conjunto de cabeçalhos a serem definidos. Se o valor do cabeçalho for igual a 'NULL', este será descartado.

Exemplos:

// Alertando o usuário que não possui um navegador com suporte a AJAX
var ajax = new SmartAjax({}, {'noAjax', function(){alert('Navegador sem suporte a AJAX');}});

// Definindo a URL padrão como a página de busca do google
var ajax = new SmartAjax({'url':'http://google.com/search'});

// Definindo valores iniciais para o evento timeout
var ajax = new SmartAjax({'timeout':20000}, {'timeout':function(){ alert('tempo esgotado!'); }});

// Definindo um cabeçalho inicial
var ajax = new SmartAjax({}, {}, {'content-type': 'text/plain'});

- setParam( String name, String value );

- setParam( Object params );

 

Altera os parâmetros do objeto SmartAjax. Pode receber apenas um parâmetro no primeiro formato, ou vários parâmetros em um objeto, no segundo formato.

Parâmetros:

  • URI url: A página a ser requisitada.
  • String method [GET]: O método de requisição (o objeto funciona perfeitamente com POST, GET, REST e SOAP).
  • Boolean async [TRUE]: Se a requisição será assíncrona ou se deverá bloquear o uso do navegador enquanto estiver em execução.
  • Number timeout [30000]: Tempo de espera da requisição em milissegundos. Deve ser menor que o timeout definido no servidor, caso contrário o objeto retornará o erro 504 ao invés de chamar o callback de timeout.

Exemplos

// Definindo de maneira única a propriedade URL
SmartAjax.setParam('url','http://forum.imasters.com.br');

// Definindo as propriedades METHOD e TIMEOUT
SmartAjax.setParam({'method' : 'post', 'timeout' : 20000});

- setEvent( String event, Function callback );

- setEvent( Object events );

 

Atrela uma função a um determinado evento. Pode receber apenas uma função vinculada a um único evento ou receber um objeto contendo o mapa evento=callback.

Eventos:

  • Function abort: Bloco de código a ser executado ao se cancelar uma requisição.
  • Function complete: Comandos realizados na completude da requisição.
  • Function error: Instruções realizadas caso um erro seja detectado.
  • Function noAjax: Bloco de instruções a serem realizadas caso não haja suporte a requisições XMLHttp.
  • Function timeout: Aguarda a requisição até o tempo definido pelo parâmetro timeout. Caso o tempo se esgote, chama esta função.
  • Function update: Realiza esta chamada cada vez que a propriedade readyState do objeto XmlHttpRequest mudar.

Exemplos

// Definição direta do evento ABORT, passando diretamente uma função como parâmetro de callback.
SmartAjax.setEvent('abort', function(){alert('requisição cancelada');});

// Criando uma função que será utilizada de callback para o evento TIMEOUT
function timeout(){alert('tempo esgotado!');}

// Definição dos callbacks para os eventos COMPLETE e TIMEOUT.
// Veja que em COMPLETE, passamos uma função que recebe um argumento, o objeto XMLHttpRequest.
// Veja, também, que para TIMEOUT, apenas informamos o nome da função de callback (sem os parênteses).
SmartAjax.setEvent({'complete': function(xhr){alert(xhr.responseText);}, 'timeout': timeout});

// Gerando erros para a falta de suporte AJAX e erros HTTP
var noAjax = function(){ throw new Error('Não há suporte a requisições XMLHttp'); }
var httpError = function(errObject){ throw errObject; }

SmartAjax.setEvent({'noAjax':noAjax, 'error':httpError});

- setHeader( [string name[, String value]] );

- setHeader( [Object headerList] );

 

Modifica a tabela de cabeçalhos adicionando novos ou editando os existentes. Recebe um único cabeçalho em dois parâmetros 'nome' e 'valor' ou um mapa no formato nome=valor. Caso o valor do header seja do tipo NULL, o header será excluído. Se o método for chamado sem argumentos, a tabela de headers será esvaziada.

 

Exemplos

// Definição direta do cabeçalho CONTENT-TYPE
SmartAjax.setHeader('content-type', 'text/plain');

// Definição de dois cabeçalhos ao mesmo tempo
SmartAjax.setHeader({'content-type':'text/plain','accept':'text/plain'});

// Definição de um cabeçalho enquanto exclui-se outro
SmartAjax.setHeader({'content-type':'text/plain','HTTP_X_REQUESTED_WITH':null});

// Exclusão direta de apenas um cabeçalho.
SmartAjax.setHeader('HTTP_X_REQUESTED_WITH', null);

// Exclusão de todos os cabeçalhos
SmartAjax.setHeader();

- abort();

 

Cancela uma requisição em andamento e, após isso, chama o callback definido em ABORT.

 

Exemplo

// Definição do callback para o evento ABORT
SmartAjax.setEvent('abort', function(){alert('requisição cancelada');});

// Chamada
SmartAjax.abort();

- send( [Object data] );

 

Prepara o objeto XMLHttpRequest, configura, envia cabeçalhos, define os eventos, processa os dados e efetua a requisição. Inicia a escuta dos eventos e chama os callbacks correspondentes.

 

Exemplo

// Configuramos o callback que será lançado ao concluir a requisição
SmartAjax.setEvent('complete',function(xhr){alert(xhr.responseText);});

// Enviamos dados pela requisição
SmartAjax.send({'nome':'Evandro','idade':22);

Definição

 

/**
 * Definição da classe SmartAjax
 * @author Evandro Oliveira <evandrofranco[at]gmail[dot]com>
  * @version 0.4.1 [2010-10-08 09:14 GMT-0300]
 * @license (cc) by-nd http://creativecommons.org/licenses/by-nd/3.0/
 * @link http://evandrofranco.com.br/lib/js/ajax.js
 * 
 * @param {Object} params O mapa de valores de configuração iniciais quais
 * 	serão definidos logo após a construção do objeto.
 * @param {Object} events Mapa de funções amarradas aos eventos.
 * @param {Object} headers Objeto contendo pares cabeçalho-valor a serem
 * 	definidos durante a instância do objeto.
 * 
 * @return {SmartAjax} Um novo objeto SmartAjax.
 */
var SmartAjax = function(params, events, headers){

	/** Sessão de parâmetros */
	var param = new Object();
	
	param.url = new String('about:blank');
	param.method = new String('GET');
	param.async = new Boolean(true);
	param.timeout = new Number(30000);
	param.username = new String(null);
	param.password = new String(null);
	
	var defParam = function(name, value){
		var types = new Object();
		types.url = 'string';
		types.method = 'string';
		types.async = 'boolean';
		types.timeout = 'number';
		types.username = 'string';
		types.password = 'string';
		if (param[name] != undefined && typeof(value) == types[name]) 
			param[name] = value;
	}
	
	/**
	 * Função de configuração de parâmetros.
	 *
	 * @param {String} name O nome do parâmetro.
	 * @param {Mixed} value O novo valor do parâmetro.
	 *
	 * @param {Object} name Mapa de parâmetros passado como objeto.
	 *
	 * @return {Self}
	 */
	this.setParam = function(name, value){
		if (typeof(name) == 'string') 
			defParam(name, value);
		else 
			if (typeof(name) == 'object') 
				for (var i in name) 
					defParam(i, name[i]);
		return this;
	}
	
	/** Sessão de eventos */
	var event = new Object();
	
	event.abort = function(){
	};
	event.complete = function(){
	};
	event.error = function(err){
		throw err;
	};
	event.noAjax = function(){
		throw new Error('Sem suporte a XMLHttp');
	};
	event.timeout = function(){
	};
	event.update = function(){
	};
	
	var defEvent = function(name, callback){
		if (typeof(callback) == 'function' && typeof(event[name]) == 'function') 
			event[name] = callback;
	}
	
	/**
	 * Função de definição de eventos.
	 *
	 * @param {String} name O nome do evento.
	 * @param {Function} callback Função (callback) a ser lançada quando o
	 * 	evento especificado acontece.
	 *
	 * @param {Object} name Mapa de eventos:callbacks que podem ser
	 * 	definidos com uma única chamada de método.
	 *
	 * @return {Self}
	 */
	this.setEvent = function(name, callback){
		if (typeof(name) == 'string') 
			defEvent(name, callback);
		else 
			if (typeof(name) == 'object') 
				for (var i in name) 
					defEvent(i, name[i]);
		return this;
	}
	
	/** Sessão de cabeçalhos */
	var header = new Object();
	
	var defHeader = function(name, value){
		if (typeof(name) == 'string' && typeof(value) == 'string') 
			header[name] = value;
	}
	
	/**
	 * Função para configuração de cabeçalhos.
	 * Chamar este método sem argumentos esvazia a tabela de cabeçalhos.
	 *
	 * @param {String} name Nome do cabeçalho.
	 * @param {String} value Novo valor do cabeçalho. Se este valor não for
	 * 	do tipo String, o cabeçalho será excluído.
	 *
	 * @param {Object} name Mapa de cabeçalhos para definição em chamada
	 * 	única. Similar ao modo de chamada simples, quando o valor do
	 * 	cabeçalho difere do tipo String, o mesmo é descartado da tabela.
	 *
	 * @return {Self}
	 */
	this.setHeader = function(name, value){
		if (arguments.length == 0) 
			header = new Object();
		else 
			if (typeof(name) == 'string') 
				if (typeof(value) != 'string') 
					delete header[name];
				else 
					header[name] = value;
			else 
				if (typeof(name) == 'object') 
					for (var i in name) 
						this.setHeader(i, name[i]);
		return this;
	}
	
	/** Sessão do objeto XMLHttp */
	var xhr = new XMLHttpRequest();
	
	/**
	 * Função de abortagem de requisição.
	 * Cancela uma requisição em andamento e chama o callback amarrado ao
	 * 	evento 'abort'.
	 */
	this.abort = function(){
		try {
			xhr.abort();
		} 
		catch (e) {
		};
		event.abort();
	};
	
	/**
	 * Função de início de requisição.
	 * Prepara o objeto XMLHttp com as configurações definidas nos
	 * 	parâmetros através do método setParam e do argumento 'params' no
	 * 	método construtor.
	 * Cria as escutas dos eventos definidos no método setEvent e no
	 * 	argumento 'events' do método construtor.
	 * Envia os cabeçalhos definidos em setHeader e no argumento 'headers'
	 * 	do método construtor ao objeto XMLHttp.
	 * Processa os dados (se) recebidos pelo parâmetro 'data'.
	 * Efetua a requisição, aguarda os eventos e lança os callbacks
	 * 	correspondentes.
	 *
	 * @param {Mixed} data Se este parâmetro é do tipo {String}, o mesmo é
	 * 	enviado sem processamentos ao servidor.
	 * Caso seja do tipo {Array}, efetua uma concatenação entre os termos
	 * 	através do caractere '&'.
	 * Caso seja do tipo {Object}, fará a conversão entre propriedade-valor
	 * 	para o formato URI, e envia os dados.
	 */
	this.send = function(data){
		if (xhr.readyState == -1) 
			return event.noAjax();
		if (typeof(data) != 'string') {
			if (!(data instanceof Array)) {
				var newData = new Array();
				for (var i in data) 
					newData.push(i + '=' + data[i]);
				data = newData;
			}
			data = data.join('&');
		}
		xhr.open(param.method, param.url + '?' + data, param.async, param.username, param.password);
		if (param.async) 
			xhr.onreadystatechange = function(){
				if (xhr.readyState != 4) 
					event.update(xhr.readyState);
				else 
					if (xhr.status != 200) 
						event.error(new Error(xhr.status + ' ' + xhr.statusText));
					else 
						event.complete(xhr);
			}
		else 
			xhr.onreadystatechange = undefined;
		for (var i in header) 
			xhr.setRequestHeader(i, header[i]);
		setTimeout(function(){
			xhr.abort();
			event.timeout();
		}, param.timeout);
		try {
			xhr.send(data)
		} 
		catch (e) {
			event.error(e);
		};
		if (!param.async) 
			event.complete(xhr);
	};
	
	this.setHeader('content-type', 'application/x-www-form-urlencoded');
	this.setHeader('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest');
	
	if (typeof(params) == 'object') 
		for (var i in params) 
			this.setParam(i, params[i]);
	if (typeof(events) == 'object') 
		for (var i in events) 
			this.setEvent(i, events[i]);
	if (typeof(headers) == 'object') 
		for (var i in headers) 
			this.setHeader(i, headers[i]);
	
	return this;
};
 
if (!window.XMLHttpRequest) 
	var XMLHttpRequest = function(){
		var ret = new Object();
		ret.open = function(){
		};
		ret.setRequestHeader = function(){
		};
		ret.readyState = -1;
		var tryes = new Array("MSXML2.XMLHTTP.7.0", "MSXML2.XMLHTTP.6.0", "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP");
		do {
			try {
				ret = new ActiveXObject(tryes[0]);
			} 
			catch (e) {
				tryes.splice(0, 1);
			}
		}
		while (ret.readyState == -1 && tryes.length);
		return ret;
	};

 

 

Download:

-
[6.9K]

-
[3K]

 

Atenção!

Não utilize os links diretos! Faça o download, hospede em seu servidor para utilização. A ferramenta está em constante atualização e pode provocar erros no seu sistema se for utilizado o source original.

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.