Ir para o conteúdo

Myajax


Criado por Rick =), Out 26 2010 13:31

2 respostas neste tópico
  • Por favor, faça o login para responder

#1 Rick =)

Rick =)
  • Rick =)
  • Colaborador
  • 16 Revisões

Revisou 26 outubro 2010 - 13:31

Salve, salve, galera!!!

Resolvi criar uma conta aqui no repositório do iMasters e compartilhar alguns códigos com vocês.
Muitos deles já constam nos laboratórios de scripts do fórum, mas a idéia aqui é criar um local separado para isso, então vamos lá.

Esta classe é uma implementação para facilitar o uso de Ajax em nossas aplicações.
Não há nada aqui que não seja do core do Javascript 1.5, ou seja, não há dependências de nenhuma biblioteca, o código abaixo é tudo o que você precisa.

Já faz um tempinho que brinco com esta aqui, tanto que a versão que posto aqui já é a 4.1

/**
 * App: myAjax
 * Versão 4.1
 * Autor: Henrique J. P. Barcelos
 * E-mail: rick.hjpbarcelos@gmail.com
 * Twitter: @rickhjpbarcelos
 * Data: 22/08/2010
 * 
 * Atenção: Este código está sob os termos da licença GPL.
 * Isso significa que você é livre para alterá-lo
 */

/*
 * Notas da versão:
 * 
 * 1. Foram adicionados os métodos getJSON e getXML e getScript
 * 2. Agora é possível executar uma função caso a requisição falhe [parâmetro de configuração 'error']
 * 3. A flag que informa ao servidor que a requisição foi feita por Ajax pode agora ser configurada.
 * 
 */

var myAjax = function(preferences){
	for (var i in myAjax.defaults) {
		this[i] = myAjax.defaults[i];
	}
	
	this.config(preferences);
}

myAjax.defaults = {
	/* xmlHttpRequest:	O objeto XmlHttpRequest, o core de uma aplicação Ajax
	 
	 * loadingID:		ID do elemento a ser exibido enquanto a requisição é processada [padrão = 'myAjaxLoading']
	 * loadingContent: 	Conteúdo do elemento a ser exibido enquanto a requisição é processada (versões anteriores: 'contentLoading')
	 * loadingWrapper: 	Elemento ou ID do elemento pai do elemento loading [padrão = tag BODY]
	 * showLoading: 	Mostrar ou não a mensagem de carregando na tela
	 * timeout:			Tempo (em ms) para remover a mensagem de carregando...
	 
	 * mode: 			Modo da requisição [TEXT, XML ou JSON]
	 * method:			Método da requisição [GET ou POST]
	 * data: 			Dados a serem enviados na requisição (versões anteriores: 'params')
	 
	 * start:			Função ou array de funções a sererm executadas no início da requisição
	 * complete:		Função ou array de funções a serem executadas ao fim da requisição
	 * error:			Função ou array de funções a serem executadas caso a requisição falhe
	 * stateChange:		Função ou array de funções a serem executadas a cada mudança de estado da requisição
	 
	 * showResponse:	Mostrar ou não a resposta da requisição diretamente no elemento HTMLObject
	 * HTMLObject:		Elemento ou ID do elemento no qual a resposta será exibida
	 
	 * url:				A URL da pagina a ser carregada
	 * flag:			Flag setada para informar a aplicação de que está lidando com uma requisição Ajax [Enviada junto com os dados da requisição]
	 * headres: 		Headers a serem enviados junto com a requisição
	 */
	xmlHttpRequest: null,
	
	loadingID: 'myAjaxLoading',
	loadingContent: 'Carregando...',
	loadingWrapper: 'body',
	showLoading: true,
	timeout: 500,
	
	mode: 'TEXT',
	method: 'GET',
	data: '',
	
	start: null,
	complete: null,
	error: null,
	stateChange: null,
	
	showResponse: true,
	HTMLObject: null,
	
	url: null,
	headers: [],
	flag: 'ajax_request',
	
	requisitionErrors: {
		400: 'Erro #400: Bad request!',
		403: 'Erro #403: Acesso proibido!',
		404: 'Erro #404: Página não encontrada!',
		408: 'Erro #408: Tempo limite atingido!',
		500: 'Erro #500: Erro interno do servidor!',
		504: 'Erro #504: Gateway offline!',
		0: 'Erro de requisição desconhecido!'
	}
};

myAjax.setDefaults = function(preferences){
	this.headers = new Array();
	if (typeof preferences == 'object') {
		for (var i in preferences) {
			if (i in myAjax.defaults) {
				myAjax.defaults[i] = preferences[i];
			}
		}
	}
};

myAjax.prototype = (function(){
	var handleExceptions = function(exception){
		throw new Error(exception);
	};
	
	var init = function(){
		//cria o objeto XMLxmlHttpRequest pra Firefox, Chrome, Opera, Safari, etc.
		try {
			this.xmlHttpRequest = new XMLHttpRequest();
		} 
		
		//cria o objeto XMLHttpRequest pra IE 6.0 e posteriormente para IE7+
		catch (e) {
			try {
				this.xmlHttpRequest = new ActiveXObject('Msxml2.XMLHTTP');
			} 
			
			catch (e) {
				this.xmlHttpRequest = new ActiveXObject('Microsoft.XMLHTTP');
			}
		}
		
		if (!this.xmlHttpRequest) {
			handleExceptions('O objeto XmlHttpRequest não pôde ser inicializado. Talvez haja suporte a AJAX no seu navegador.');
		}
	};
	
	var genQS = function(data){
		var qs = '';
		if (data != null) {
			if (data.constructor == Object) {
				for (var i in data) 
					qs += i + '=' + escape(data[i]) + '&';
				qs = qs.replace(/\&$/, '');
			}
			else if (data.constructor == String) {
				var explode = data.split('&');
				for (var i in explode) 
					explode[i] = escape(explode[i]);
				qs = explode.join('&');
			}
		}
		return qs;
	};
	
	var readyStateChange = function(){
		if (typeof this.stateChange == "function") 
			callFunctions.call(this, 'stateChange', this.xmlHttpRequest.readyState);
		
		if (this.xmlHttpRequest.readyState == 4) {
			processing.call(this, false);
			var status = this.xmlHttpRequest.status;
			if (status == 200) {
				var response = handleResponse.call(this);
				callFunctions.call(this, 'complete', response);
			}
			else {
				var error = this.requisitionErrors[status];
				callFunctions.call(this, 'error', error);
				handleExceptions(error);
			}
		}
		else {
			if (this.showLoading) processing.call(this, true);
		}
	};
	
	var processing = function(opt){
		if (opt) {
			var wrapper = this.loadingWrapper;
			var divLoading = document.getElementById(this.loadingID);
			if (!divLoading) {
				divLoading = document.createElement("div");
				divLoading.setAttribute("id", this.loadingID);
				divLoading.innerHTML = this.loadingContent;
				wrapper.insertBefore(divLoading, wrapper.lastChild.nextSibling);
			}
			else {
				divLoading.innerHTML = this.loadingContent;
			}
		}
		else {
			var self = this;
			setTimeout(function(){
				var divLoading = document.getElementById(self.loadingID);
				if (divLoading) divLoading.parentNode.removeChild(divLoading);
			}, self.timeout);
		}
	};
	
	var handleResponse = function(){
		var mode = this.mode;
		var response;
		if (typeof mode == "string") {
			mode = mode.toUpperCase();
			switch (mode) {
				case 'TEXT':
					response = this.responseText();
					if (this.showResponse) {
						if (this.HTMLObject) {
							if (this.HTMLObject.nodeName == "INPUT" ||
							this.HTMLObject.nodeName == "TEXTAREA" ||
							this.HTMLObject.nodeName == "OPTION") {
								this.HTMLObject.value = response;
							}
							else {
								this.HTMLObject.innerHTML = response;
							}
						}
						else {
							handleExceptions("Elemento contâiner inválido ou inexistente!");
						}
					}
					break;
				case 'JSON':
					response = this.responseJSON();
					break;
				case 'SCRIPT':
					response = this.responseScript();
					break;
				case 'XML':
					response = this.responseXML();
					break;
				default:
					myAjax.handExceptions('Modo inválido! Valores esperados: "TEXT" ou "XML" ou "JSON"');
			}
		}
		else {
			myAjax.handExceptions('Modo de requisição inválido!')
		}
		
		return response;
	};
	
	//Faz a chamada das funções quando a requisição for completada
	var callFunctions = function(callback, args){
		callback = this[callback];
		
		if (!callback) return false;

		if (callback.constructor == Array) {
			for (var i in callback) {
				if (typeof callback[i] == 'function') {
					callback[i].call(this, args);
				}
				else {
					handleExceptions("Função Inválida!");
				}
			}
		}
		else if (callback.constructor == Function) {
			callback.call(this, args);
		}
		else {
			handleExceptions("Função inválida ou inexistente!");
		}
	};
	
	return {
		constructor: myAjax,
		
		config: function(preferences){
			if (typeof preferences == 'object') for (var i in preferences) 
				if (i in this) this[i] = preferences[i];
			
			//Configurando o elemento contâiner
			if (this.loadingWrapper == 'body') 
				this.loadingWrapper = document.getElementsByTagName('body')[0];
			
			else if (typeof this.loadingWrapper == 'string') 
				this.loadingWrapper = document.getElementById(this.loadingWrapper);
			
			//Configurando o método
			if (typeof this.method == 'string') 
				this.method = this.method.toUpperCase();
			else 
				handleExceptions('Método inválido! Valores esperados: "GET" ou "POST"');
			
			//Configurando o modo
			if (typeof this.mode == 'string') 
				this.mode = this.mode.toUpperCase();
			else 
				handleExceptions('Modo inválido! Valores esperados: "TEXT" ou "XML" ou "JSON"');
				
			if(this.headers.constructor != Array){
				var tmp_headers = this.headers;
				this.headers = [];
				for (var i in tmp_headers) {
					var new_header = {};
					new_header[i] = tmp_headers[i];
					this.headers.push(new_header);
				}
			}
		},
		
		//Seta os headers da requisiçao
		setHeaders: function(headers){
			if (headers) {
				if (typeof headers == 'object') {
					if (headers.length) {
						this.headers = this.headers.concat(headers);
					}
					else {
						this.headers.push(headers);
					}
				}
			}
			if (this.headers.constructor == Array) {
				for (var i in this.headers) {
					for (var n in this.headers[i]) {
						this.xmlHttpRequest.setRequestHeader(n, this.headers[i][n]);
					}
				}
			}
		},
		
		load: function(url, HTMLObject, complete, error){
			if (!url) {
				handleExceptions('Você não informou a URL dá página a ser processada!');
				return false;
			}
			
			//Inicializando o objeto XMLHTTPRequest
			init.call(this);
			
			//Verifica se uma função foi setada para o início da requisição
			callFunctions.call(this, 'start');
			
			//Configurando as possíveis funções recebidas como argumento
			if(complete){
				var constr = complete.constructor;
				if(constr == Function || constr == Array)
					this.complete = complete;					
			}
			
			if(error){
				var constr = error.constructor;
				if(constr == Function || constr == Array)
					this.error = error;					
			}
			
			//Configurando o objeto HTML
			this.HTMLObject = HTMLObject;
			if (!this.HTMLObject) 
				this.showResponse = false;
			else if (typeof HTMLObject == 'string') 
				this.HTMLObject = document.getElementById(HTMLObject);
			else 
				this.HTMLObject = HTMLObject;
			
			
			this.data = genQS(this.data);
			//Se a flag está setada, precisamos adicioná-la aos dados da requisição
			if (this.flag) {
				if (this.flag.constructor != String) {
					handleExceptions('A flag setada pela requisição deve ser uma string!')
					return false;
				}
				
				if (!this.data.match(this.flag)) {
					this.data += this.data.length > 0 ? '&' : '';
					this.data += this.flag + '=' + true;
				}
			}
			
			if (this.method == 'POST') {
				//Se temos uma requisição POST, precisamos setar um header específico
				this.headers.push({
					'Content-Type': 'application/x-www-form-urlencoded'
				});
			}
			else {
				//Se temos uma requisição GET, precisamos acidionar os dados à query string do link
				var joinner = (url.toString().indexOf('?') == -1) ? '?' : '&';
				url += joinner + this.data;
				
				//Os dados não são enviados pelo objeto xmlHttpRequest em uma requisição GET
				this.data = null;
			}
			
			this.url = url;
			
			this.xmlHttpRequest.open(this.method, this.url, true);
			this.setHeaders();
			this.xmlHttpRequest.send(this.data);
			
			var self = this;
			
			this.xmlHttpRequest.onreadystatechange = function(e){
				readyStateChange.call(self);
			}
		},
		
		get: function(url, HTMLObject, complete, error){
			this.method = 'GET';
			this.load(url, HTMLObject, complete, error);
		},
		
		post: function(url, data, HTMLObject, complete, error){
			this.method = 'POST';
			this.data = data;
			this.load(url, HTMLObject, complete, error);
		},
		
		getJSON: function(url, complete, error, data){
			this.mode = 'JSON';
			this.method = data ? 'POST' : 'GET';
			this.data = data;
			this.load(url, null, complete, error);
		},
		
		getScript: function(url, complete, error, type, data){
			type = type || 'text/javascript';

			var addScript = function(script){
				var new_script = document.createElement('script');
				new_script.setAttribute('type', type);
				new_script.innerHTML = script;
				
				var head = document.getElementsByTagName('head').item(0);
				head.appendChild(new_script);
			}
			
			var callbacks = [addScript, complete];
			
			this.mode = 'SCRIPT';
			this.method = data ? 'POST' : 'GET';
			this.data = data;
			this.load(url, null, callbacks, error);
		},
		
		getXML: function(url, complete, error, data){
			this.mode = 'XML';
			this.method = data ? 'POST' : 'GET';
			this.data = data;
			this.load(url, null, complete, error);
		},
		
		responseText: function(){
			var response = this.xmlHttpRequest.responseText;
			return response;
		},
		
		responseJSON: function(){
			var evalR = function(response){
				if(response){
					switch(response.constructor){
						case Array:
							for(var i = 0; i < response.length; i++){
								response[i] = evalR(response[i]);				
							}
							break;
						case Object:
							for(var i in response){
								response[i] = evalR(response[i]);				
							}
							break;
						case String:
							response = eval('('+response+')');
							break;
					}
				}	
				return response;
			}
			
			var response = eval('('+this.responseText()+')');
			response = evalR(response);
			return response;
		},
		
		responseScript: function(){
			return this.responseText();
		},
		
		responseXML: function(){
			return this.xmlHttpRequest.responseXML;
		}
	};
})();

O seu uso é simples:

Requisição GET comum:
var ajax = new myAjax();
ajax.get('pagina.html', 'ID DO ELEMENTO QUE RECEBERÁ A RESPOSTA');

O código acima faz uma requisição para a página 'pagina.html' e carrega seu conteúdo no elemento cujo ID é o segundo parâmetro acima.
Ressalto que não há uso de bibliotecas, então não deve-se incluir o '#' antes do ID.


Requisição GET com callbacks:
Se desejar executar alguma ação quando a requisição termina ou falha.

A assinatura completa do método myAjax::get é:
myAjax::get(url, element, complete, error);

complete [function]: função ou array de funções a serem executadas quando a requisição se completa com sucesso.
error [function]: função ou array de funções a serem executadas se a requisição falha.

Exemplo:
var ajax = new myAjax();
var ajax.get('teste.php', 'principal', function(resposta){
    alert(resposta);
}, function(error){
    alert(error);
});


Requisição POST:
A diferença de uma requisição GET e uma POST é que na GET, os dados são indexados ao link através de uma query string (?dado=valor&outro_dado=outro_valor).
Na requisição POST, os dados são enviados de outra forma, no corpo da 'mensagem'.
É necessário então informar os dados a serem enviados na requisição.

A assinatura do método myAjax::post é:
myAjax::post(url, data, element, complete, error)

Todos os parâmetros são idênticos ao parâmetros do método GET, com a excessão de 'data', que representam os dados da requisição:

data [string | objetc]: deve ser uma string em formato query string (sem o '?': 'dado=valor&outro_dado=outro_valor') ou um objeto javascript ( {dado: valor, outro_dado: outro_valor} )

Requisição JSON e Script:
Também é possível fazer uma requisição por um arquivo JSON ou JS (script).
myAjax::getJSON(url, complete, error, data);
myAjax::getScript(url, complete, error, type, data);

Novamente, a lista de parâmetros são muito parecidas.
Uma pequena diferença aqui é que preencher ou não o parâmetro 'data' indica se a requisição será via POST ou GET.
Se há dados a serem enviados, assume-se que a requisição é POST, caso contrário, GET.

O parâmetro 'type' do método getScript indica o atributo 'type' que deve ser colocado na tag SCRIPT adicionada à página.
Por padrão, adiciona-se 'text/javascript'.

A usagem básica é essa.
Logo, logo ensinarem a configuração completa desta classe.
Quem já tem prática na coisa, dá uma olhada na lista de propriedades colocadas em myAjax.defaults :thumbsup:
Loading Module: Computer Engineer
|############-------------------| 50%

#2 Rick =)

Rick =)
  • Rick =)
  • Colaborador
  • 16 Revisões

Revisou 04 novembro 2010 - 00:26

Bom, voltei galera e é a hora de terminar a doc básica :lol:

Quem já tentou utilizar deve ter notado esse bando de propriedades aqui:
myAjax.defaults = {
        /* xmlHttpRequest:      O objeto XmlHttpRequest, o core de uma aplicação Ajax
         
         * loadingID:           ID do elemento a ser exibido enquanto a requisição é processada [padrão = 'myAjaxLoading']
         * loadingContent:      Conteúdo do elemento a ser exibido enquanto a requisição é processada (versões anteriores: 'contentLoading')
         * loadingWrapper:      Elemento ou ID do elemento pai do elemento loading [padrão = tag BODY]
         * showLoading:         Mostrar ou não a mensagem de carregando na tela
         * timeout:                     Tempo (em ms) para remover a mensagem de carregando...
         
         * mode:                        Modo da requisição [TEXT, XML ou JSON]
         * method:                      Método da requisição [GET ou POST]
         * data:                        Dados a serem enviados na requisição (versões anteriores: 'params')
         
         * start:                       Função ou array de funções a sererm executadas no início da requisição
         * complete:            Função ou array de funções a serem executadas ao fim da requisição
         * error:                       Função ou array de funções a serem executadas caso a requisição falhe
         * stateChange:         Função ou array de funções a serem executadas a cada mudança de estado da requisição
         
         * showResponse:        Mostrar ou não a resposta da requisição diretamente no elemento HTMLObject
         * HTMLObject:          Elemento ou ID do elemento no qual a resposta será exibida
         
         * url:                         A URL da pagina a ser carregada
         * flag:                        Flag setada para informar a aplicação de que está lidando com uma requisição Ajax [Enviada junto com os dados da requisição]
         * headres:             Headers a serem enviados junto com a requisição
         */
        xmlHttpRequest: null,
        
        loadingID: 'myAjaxLoading',
        loadingContent: 'Carregando...',
        loadingWrapper: 'body',
        showLoading: true,
        timeout: 500,
        
        mode: 'TEXT',
        method: 'GET',
        data: '',
        
        start: null,
        complete: null,
        error: null,
        stateChange: null,
        
        showResponse: true,
        HTMLObject: null,
        
        url: null,
        headers: [],
        flag: 'ajax_request',
        
        requisitionErrors: {
                400: 'Erro #400: Bad request!',
                403: 'Erro #403: Acesso proibido!',
                404: 'Erro #404: Página não encontrada!',
                408: 'Erro #408: Tempo limite atingido!',
                500: 'Erro #500: Erro interno do servidor!',
                504: 'Erro #504: Gateway offline!',
                0: 'Erro de requisição desconhecido!'
        }
};

Vamos por partes:
* loadingID (string): ID do elemento a ser exibido enquanto a requisição é processada [padrão = 'myAjaxLoading']
* loadingContent (string): Conteúdo do elemento a ser exibido enquanto a requisição é processada (versões anteriores: 'contentLoading')
* loadingWrapper (string | HTMLNode): Elemento ou ID do elemento pai do elemento loading [padrão = tag BODY]
* showLoading (bool): Mostrar ou não a mensagem de carregando na tela
* timeout (integer): Tempo (em ms) para remover a mensagem de carregando...

Não quer uma mensagem 'carregando' na tela?
var ajax = new myAjax({
   showLoading: false
});
ajax.get('pg.html', 'conteudo');
Irá carregar a página 'pg.html' na div com id 'conteudo' SEM mostrar a mensagem 'carregando'...

Você também pode alterar o ID do elemento que contém tal mensagem à sua preferência, tal qual também é possível alterar o elemento ao qual a mensagem é adicionada como filha
var ajax = new myAjax({
   loadingID: 'meuID'
   loaddingWrapper: 'conteudo'
});
ajax.get('pg.html', 'conteudo');
A mensagem 'carregando' será adicionada ao elemento de id 'conteudo' e terá o id 'meuID'

Que raio de mensagem o que? Eu quero uma IMAGEM, um gif animado enquanto a requisição é processada

Pois sim:
var ajax = new myAjax({
   loadingContent: '<img src="images/loading.gif" alt="carregando"/>'
});
ajax.get('pg.html', 'conteudo');
____________________________________________________________________________________________________________

Muitas das outrar propriedades são configuradas automaticamente quando se faz as chamadas dos métodos:
* mode: 'TEXT', //Muda automaticamente para JSON quando se usa o método getJSON, para XML quando se usa getXML, etc...
* method: 'GET', //Muda automaticamente para POST quando se usa o método POST
* data: '', //É preenchido quando se passa o parâmetro homônimo para os métodos antes citados
___________

start: null, //Callback executado quando a execução começa
complete: null, //Informado nos métodos
error: null, //Informado nos métodos
stateChange: null, //Função executada quando a requisição muda de estado

___________

* showResponse: true, //Decide se a resposta será mostrada diretamente dentro do elemento ou não
* HTMLObject: null, //O objeto que receberá a resposta. Se for null, o parâmetro acima é setado para false automaticamente

___________
* url: null, //A url informada nos métodos get, post, getJSON, etc...
* flag: 'ajax_request', //Juntamente com os dados, é enviado uma flag avisando a aplicação que trata-se de uma requisição Ajax [acredite, é útil]
A flag é adicionada ao final dos dados da requisição. Quando se faz algo do tipo:
var ajax = new myAjax();
ajax.post('pg.html', {chave: valor});

No final, após codificar os dados, é enviada uma query string da forma:
'chave=valor'
A classe já adiciona automaticamente a flag, assim, os dados enviados são:
'chave=valor&ajax_request=true'
__________

* headers: [], //Headers enviados com a requisição... Deve ser um array de objetos no formato [{header:'valor do header'}]

Exemplo:
var ajax = new myAjax({
   headers: [{pragma: 'no-cache'}]
});
ajax.get('pg.html', 'conteudo');

__________

Por fim, aqui estão as mensagens enviadas para o console de erros caso algo ocorra de maneira errada
requisitionErrors: {
     400: 'Erro #400: Bad request!',
     403: 'Erro #403: Acesso proibido!',
     404: 'Erro #404: Página não encontrada!',
     408: 'Erro #408: Tempo limite atingido!',
     500: 'Erro #500: Erro interno do servidor!',
     504: 'Erro #504: Gateway offline!',
     0: 'Erro de requisição desconhecido!'
}

______________________________________________________________________________________________________________________

Agora, voltando ao exemplo da imagem gif de loading:
var ajax = new myAjax({
   loadingContent: '<img src="images/loading.gif" alt="carregando"/>'
});
ajax.get('pg.html', 'conteudo');

E se eu quiser essa imagem em todas as requisições que eu fizer? Vou precisar repetir o
loadingContent: '<img src="images/loading.gif" alt="carregando"/>'
em todas elas?

Jamais!!! :thumbsup:
Justamente pensando nisso há o método estático 'setDefaults'...
Tudo o que tem a fazer é chamá-lo no início do seu script passando um objeto com as propriedades que deseja alterar o valor padrão:

myAjax.setDefaults({
   loadingContent: '<img src="images/loading.gif" alt="carregando"/>'
});

Pronto!!! Agora todas as requisições Ajax que fizeres em qualquer lugar desse script terão a tal imagem de loading...

Bem, é isso ae...

Comentem, divulguem... Enfim... reajam B)
Loading Module: Computer Engineer
|############-------------------| 50%

#3 Franklin Javier

Franklin Javier
  • Franklin Javier
  • Colaborador
  • 6 Revisões

Revisou 21 fevereiro 2011 - 12:47

Parece ser muito boa, vou analisar e dar meu feedback.




1 usuário(s) está(ão) lendo este código

1 membro(s), 0 visitante(s) e 0 membros anônimo(s)