Ir para conteúdo

POWERED BY:

Arquivado

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

Henrique Barcelos

[Resolvido] Conteúdo Auto-Editável

Recommended Posts

Boa noite, galëre...

 

Depois de um tempo longe do fórum, retorno hoje com um tutorial sobre como utilizar um plug-in jquery criado por mim para fazer edição de conteúdo.

A versão antiga do orkut tinha uma funcionalidade parecida.

 

Então, chega de papo e vamos ao código:

 

Como já dito, trata-se de um plug-in jQuery.

O código foi concebido utilizando a versão 1.3, mas funciona perfeitamente com a versão 1.4.

/**
 * Autor: Henrique J. P. Barcelos
 * E-mail: rick.hjpbarcelos@gmail.com
 * Twitter: @rickhjpbarcelos
 * Data: 02/02/2010
 * Versão 3.0b
 * 
 * Atenção: Este código está sob os termos da licença GPL.
 * Isso significa que você é livre para alterá-lo,
 * desde que cite a fonte original
 */

/*
 * Notas da versão:
 * 
 * 1. A aplicação myEditable agora passa a ser um plug-in jQuery, para facilitar ainda mais seu uso
 * 2. Além de campos do tipo texto (input), agora também é possével escolher entre textarea e select
 * 
 */

(function($){
	function handExceptions(msg){
		throw new Error(msg);
		return false;
	}
	
	$.fn.myEditable = function(preferences){
		return this.each(function(){
			new $.myEditable(this, preferences);
		});
	};
	
	$.myEditable = function(elem, preferences){
		var defaults = $.myEditable.defaults;
		for(var i in defaults){
			this[i] = defaults[i];
		}
		
		this.config(preferences);
		
		this.makeChanges = true;
		this.finished = false;
		this.editable = null;
		this.selector = $(elem);
		
		this.init();
	};
	
	$.extend($.myEditable, {
		//Opções configuráveis
		defaults: {
			startEvent: 'dblclick', 	//Evento que inicia as ações
			cancelEvent: 'mouseout',	//Evento que cancela a criação do elemento editável
			finishEvent: 'blur', 		//Evento que finaliza as ações
			timeout: 1,					//Delay (em ms) para a criação do elemento editável
			
			createCallback: null, 		//Função executada ao criar o elemento editável
			finishCallback: null, 		//Função executada ao se capturar o evento de 'finishEvent'
			keyupCallback: null, 		//Função executada ao se digitar dentro do elemento editável
			startCallback: null, 		//Função executada ao se capturar o evento de 'startEvent'
			submitCallback: null,		//Função executada quando a edição se dá com sucesso
			validateCallback: null,		//Função que faz a validação do valor digitado, deve retornar TRUE ou FALSE
			
			content: 'html', 			//Conteúdo a ser editado [Padrão = innerHTML, mas pode ser qualquer atributo]
			originalValue: '', 			//Valor inicial do elemento
			editableID: null,			//ID do elemento editável criado
			
			type: 'input', 				//Define se o elemento criado será um INPUT, um TEXTAREA ou um SELECT
			optionsList: {				//Lista de opções de um select box. Requerido caso o tipo seja select
				'' : 'Selecione...'
			}, 
			
			//Requerimento: Plug-in Masked Input http://plugins.jquery.com/project/maskedinput
			mask: null,					//Função para criar uma máscara para um campo INPUT ou TEXTAREA [necessita do plug-in 'Masked Input' para funcionar]
			
			speed: 'fast', 				//Velocidade da animação
			
			keyConfirm: 13, 			//Enter para confirmar [CTRL+Enter, caso esteja usando o tipo textarea]
			keyCancel: 27 				//Esc para cancelar
		},
		
		setDefaults: function(preferences){
			for(var i in preferences){
				if(i in $.myEditable.defaults){
					$.myEditable.defaults[i] = preferences[i];
				}
			};
		},
		
		prototype: {
			config: function(preferences){
				for(var i in preferences){
					if(i in this){
						this[i] = preferences[i];
					}
				}	
			},
			
			init: function(){
				var self = this;
				var timer;
				
				this.selector.bind(this.startEvent, function(e){
					e = e || window.event;
					timer = setTimeout(function(){
						self.start.call(self, e);
					}, self.timeout);
				});
				
				this.selector.bind(this.cancelEvent, function(e){
					e = e || window.event;
					clearTimeout(timer);
				});
				
			},
			
			start: function(e){
				if(typeof this.startCallback == "function"){
					this.startCallback.call(this);
				}
				
				this.makeChanges = true;

				if(this.content == 'html'){
					this.originalValue = this.selector.html();
				} else {
					this.originalValue = this.selector.attr(this.content);
				}
				
				var self = this;
				this.originalValue = $.trim(this.originalValue);
				
				this.selector.fadeOut(this.speed, function(){
					self.createElement.call(self);
				});
			},
			
			createElement: function(){
				if(this.selector.prev().hasClass('myEditable')) return false;
				
				switch(this.type){
					case "input":
						this.selector.before("<input class=\"myEditable myEditableInput\" value=\""+this.originalValue+"\"/>");
						this.editable = this.selector.prev();
						break;
					case "textarea":
						this.selector.before("<textarea class=\"myEditable myEditableTextarea\" cols=\"20\" rows=\"10\">"+this.originalValue+"</textarea>");
						this.editable = this.selector.prev();
						break;
					case "select":
						this.selector.before("<select class=\"myEditable myEditableSelect\"></select>");
						this.editable = this.selector.prev();
						this.getOptionsList();
						break;
					default:
			 	handExceptions("Tipo de elemento inválido");
						this.abort();
				};
				
				if(this.type == "input" || this.type == "textarea"){
					//Só aplicará a mascara se o plugin 'mask' estiver incluso na página
					if(typeof $.fn.mask == "function"){
						if (this.mask) {
							this.editable.mask(this.mask);
						}
					}
				}
				
				if(typeof this.createCallback == "function"){
					this.createCallback.call(this);
				}

				this.editable.focus();
				this.activate();
			},
			
			activate: function(){
				var self = this;
				self.finished = false;
				this.editable.bind(this.finishEvent, function(e){
					e = e || window.event;
					if (!self.finished) {
						self.finish.call(self, e);
					}
				});
				
				this.editable.keyup(function(e){
					e = e || window.event;
					
					if(typeof self.keyupCallback == "function"){
						self.keyupCallback.call(self);
					}
					
					if(e.keyCode == self.keyCancel){
						self.abort.call(self, e);
						self.finish.call(self, e);
					}
					
					if(e.keyCode == self.keyConfirm){
						if(this.type == "textarea"){
							if(self.keyConfirm == 13){
								if(e.ctrlKey == false)
									return false;
							}
						}
						self.finish.call(self, e);
					}
				});
			},
			
			
			getOptionsList: function(){
				if (!this.optionsList) {
					handExceptions("Não há nenhuma opção para inserir!");
					this.abort();
				}
					
				var select = this.editable;
				if (this.optionsList.length == undefined) {
					for (var i in this.optionsList) {
						select.append("<option value=\"" + i + "\">" + this.optionsList[i] + "</option>");
					}
				} else {
					for(var n = 0; n < this.optionsList.length; n++){
						var self = this;
						(function(){
							var opt = self.optionsList[n];
							for (var i in opt) {
								select.append("<option value=\"" + i + "\">" + opt[i] + "</option>");
							}
						})();
					}
				};
			},
			
			abort: function(){
				this.makeChanges = false;
			},
			
			finish: function(e){
				if(typeof this.finishCallback == "function"){
					this.finishCallback.call(this);
				}
				
				var self = this;
				
				var original = this.originalValue;
				var new_val = $.trim(this.editable.val());
				
				if(new_val == "" || new_val === original){
					this.makeChanges = false;
				} 
				
				if(this.makeChanges){
					if(typeof this.validateCallback == "function"){
						var validate = this.validateCallback.call(this, new_val);
						if(!validate){
							this.makeChanges = false;
						}
					}
				}
				
				if(this.makeChanges){	
					if(typeof this.submitCallback == "function"){
						this.submitCallback.call(this, new_val);
					}
					
					//Correção especial para o caractere '&'
					new_val = new_val.replace(/\&/, "&");
					if(this.type == "select"){
						new_val = this.optionsList[new_val];
					}
					this.selector.html(new_val);
				}
				
				if (this.editable.hasClass("myEditable")) {
					this.editable.fadeOut(this.speed, function(){
						self.selector.fadeIn();
						self.editable.remove();
					});
				}
				this.finished = true;
			}
		}
	});
	
})(jQuery);

Utilizando:

 

O básico:

 

$(selector).myEditable();

Dando um duplo clique no elemento um campo input do tipo text será criado sendo possível editar o conteúdo...

 

ENTER confirma a edição do conteúdo e ESC cancela, retornando ao valor inicial...

Alterando os eventos:

 

$(selector).myEditable({
	startEvent: 'click'
});

Desse modo, apenas um clique simples no elemento ativa o plug-in;

 

$(selector).myEditable({
	startEvent: 'mouseover',
	cancelEvent: 'mouseout',
	timeout: 3000
});

Desse modo, ao passar o mouse sobre o elemento, o plug-in é ativado, porém com um delay de 3 segundos.

A opção cancelEvent informa qual evento pode cancelar a ativação do plug-in antes do intervalo timeout se completar

 

 

Não só inputs, textareas e selects também:

$(selector).myEditable({
	type: 'textarea'
});

A única diferença para o modo input é que a edição é confirmada através da combinação CTRL+ENTER, já que um textarea é multi-linha e a tecla ENTER é usada para criar novas linhas...

 

$(selector).myEditable({
 	type: 'select',
	optionsList: {
 'VALOR DA OPÇÃO 1': 'LABEL DA OPÇÃO 1', 
 	'VALOR DA OPÇÃO 2': 'LABEL DA OPÇÃO 2',
 	...
	}
 });

Quando utilizar o modo select, você deve informar as opções que devem ser apresentadas no select box...

optionsList deve ser um objeto cujas propriedades são os valores da opção (atributo value da tag option) e os valores são o label da opção, ou seja, o texto que aparece no select box...

 

Editando outros atributos:

Por padrão, o plug-in edita o valor da propriedate innerHTML da tag...

Isso pode ser alterado através da opção content:

 

$(selector).myEditable({
 	content: 'title'
});

Desse modo você altera o atributo title do seletor. Às vezes pode ser útil ;]

 

Os Callbacks:

 

Mas e daí? Altero o valor e faço o que depois?

Atualizo a página e o valor volta ao inicial...

É possível editar informações vindas de um banco de dados e salvar depois?

 

Claro... como não?

 

Para isso existem os callbacks:

 

createCallback: função chamada assim que o elemento editável (input, textarea ou selectbox) é criado...

É bem útil quando se deseja adicionar funcionalidades, como por exemplo máscaras de diferentes tipos de campos...

 

startCallback: função chamada assim que o evento starEvent ocorre.

finishCallback: função chamada assim que o evento finishEvent ocorre, ou seja, quando a edição termina.

keyupCallback: função executada ao se digitar dentro do elemento editável. Claramente, só é válida para inputs e textareas

validateCallback: função que realiza a validação do valor digitado ou selecionado. É chamada quando o evento finishEvent ocorre, mas somente se o valor for alterado.

Importante que ela deve retornar um valor booleano (TRUE ou FALSE)

 

submitCallback: ao finalizar a edição, o script verifica se foi apertado ENTER (ou CTRL+ENTER) para executar a edição ou ESC para cancelar.

Este callback somente é chamado no primeiro caso e se, e somente se o valor inicial foi alterado...

 

A mágica acontece justamente neste último evento.

Dentro dele, é possível se enviar o novo valor através de uma requisição, sendo através de AJAX ou não.

 

$(selector).myEditable({
 	submitCallback: function(valor_editado){
 	var data = {
 	novo_valor: valor_editado
 	}
 	$.post("editar_valor.php", data, function(){
 	alert("Editado");
 	});
	}
});

Pode-se facilmente enviar o novo valor por uma requisição AJAX.

A função submitCallback recebe como parâmetro o valor editado pelo usuário...

 

Adicionando uma máscara:

Esta opção utiliza o excelente plug-in Masked Input:

http://plugins.jquer...ect/maskedinput

 

Caso ele não esteja instalado, a opção deixa de funcionar...

 

É útil no caso de você desejar editar uma data, por exemplo:

 

$(selector).myEditable({
 	mask: '99/99/9999'
});

Outras opções

 

[i]mask[/i]: null, //Função para criar uma máscara para um campo INPUT ou TEXTAREA [necessita do plug-in 'Masked Input' para funcionar]
			
[i]speed[/i]: 'fast', 				//Velocidade da animação
			
[i]keyConfirm[/i]: 13, //Código da tecla para confirmar a edição [Padrão = ENTER]
[i]keyCancel[/i]: 27 	 //Código da tecla para cancelar a edição [Padrão = ESC]

Is-ss-ss-so é-é-é tu-tudo pessoal...

 

Dúvidas, postem xD

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.