Index: sandbox/2.4.2-expresso1/prototype/modules/calendar/js/task.helpers.js
===================================================================
--- sandbox/2.4.2-expresso1/prototype/modules/calendar/js/task.helpers.js	(revision 6981)
+++ sandbox/2.4.2-expresso1/prototype/modules/calendar/js/task.helpers.js	(revision 6990)
@@ -562,4 +562,319 @@
         }
     });
+    
+    UI.dialogs.addTask.find(".attendee-list-add .add-attendee-input input").Watermark("digite um email para convidar");
+    /* 
+    * Trata a edição de um novo participante adicionado
+    */
+    var hasNewAttendee = false;
+
+    blkAddAtendee.find('.attendee-list-add .add-attendee-input span').click(function(data){
+	blkAddAtendee.find('.attendee-list-add .add-attendee-input input').keydown();
+    });
+
+    blkAddAtendee.find('.attendee-list-add .add-attendee-input input').keydown(function(event) {
+	if (event.keyCode == '13' && $(this).val() != '' || (event.keyCode == undefined && $(this).val() != '')) {
+	    Encoder.EncodeType = "entity";
+	    $(this).val(Encoder.htmlEncode($(this).val()));
+
+	    newAttendeeEmail = false;
+	    newAttendeeName  = false;
+	    skipAddNewLine   = false;
+
+	    var info = $(this).val();
+
+	    /**
+	    * email válido?
+	    */
+	    info.match(/^[\w!#$%&'*+\/=?^`{|}~-]+(\.[\w!#$%&'*+\/=?^`{|}~-]+)*@(([\w-]+\.)+[A-Za-z]{2,6}|\[\d{1,3}(\.\d{1,3}){3}\])$/) ? 
+	    newAttendeeEmail = info : newAttendeeName = info;
+
+	    /**
+	    * 1) busca no banco para saber se o usuário já existe
+	    *		1.1) se existe, atualiza as info na lista de participantes e nao abre o tooltip
+	    *		1.2) se não existe
+	    *			a) salva como novo usuario externo no banco (apenas com email)
+	    *			b) exibe tooltip pedindo o nome
+	    *			c) se o usuário preenche tooltip e salva, atualiza com o nome o usuário recém criado
+	    *			d) se o usuário cancela o tooltip, fica o usuário salvo apenas com email e sem nome
+	    */
+
+	    var user = DataLayer.get('user', ["=", "mail", $(this).val()]);
+	    if(!!user && user[0].id)
+		attendees[user[0].id] = {
+		    name: user[0].name
+		    };
+
+	    /**
+	    * guarda o último tooltip aberto referente à lista de participantes 
+	    */
+	    lastEditAttendeeToolTip = [];
+
+	    /**
+	    * Valida email e salva um participante externo 
+	    */
+	    var saveContact = function() {
+		Encoder.EncodeType = "entity";
+
+		var currentTip = $('.qtip-active');
+		newAttendeeName  = currentTip.find('input[name="name"]').val();
+		newAttendeeEmail = currentTip.find('input[name="mail"]').val();
+
+		if (!(!!newAttendeeEmail.match(/^[\w!#$%&'*+\/=?^`{|}~-]+(\.[\w!#$%&'*+\/=?^`{|}~-]+)*@(([\w-]+\.)+[A-Za-z]{2,6}|\[\d{1,3}(\.\d{1,3}){3}\])$/))) {
+		    currentTip.find('.messages').removeClass('hidden').find('.message label').html('Email inválido.');
+		    return false;
+		}
+
+		DataLayer.put('user', {
+		    id:userId, 
+		    name:newAttendeeName, 
+		    mail:newAttendeeEmail, 
+		    isExternal:isExternal
+		});
+
+		lastEditAttendeeToolTip.find('label')
+		.filter('.name').html(Encoder.htmlEncode(newAttendeeName)).attr('title', Encoder.htmlEncode(newAttendeeName)).end()
+		.filter('.mail').html(Encoder.htmlEncode(newAttendeeEmail)).attr('title', Encoder.htmlEncode(newAttendeeEmail));
+
+		blkAddAtendee.find('.attendee-list-add .add-attendee-input input').val('');
+		return true;
+	    }
+
+	    /**
+	    * Formata e adequa um tootip abert para edição de um participante na lista
+	    */
+	    var onShowToolTip = function(arg0) {
+		$('.qtip-active .button.close').button({
+		    icons: {
+			primary: "ui-icon-close"
+		    },
+		    text: false
+		});
+		$('.qtip-active .button').button()
+		.filter('.save').click(function(event, ui) {
+		    if(saveContact())
+			lastEditAttendeeToolTip.qtip("destroy");
+		    else
+			return false;
+		}).end()
+		.filter('.cancel').click(function(event, ui) {
+		    lastEditAttendeeToolTip.qtip("destroy");
+		})
+
+		/** 
+		* Trata o ENTER no campo da tooltip, equivalente a salvar 
+		* o novo convidado.
+		*/
+		$('.qtip-active input').keydown(function(event) {
+		    if (event.keyCode == '13') {						
+			if (saveContact())						
+			    lastEditAttendeeToolTip.qtip("destroy");
+
+			lastEditAttendeeToolTip.qtip("destroy");
+			event.preventDefault();
+		    }
+		})
+		.filter('[name="name"]').Watermark("informe o nome do contato").end()
+		.filter('[name="mail"]').Watermark("informe o email do contato");
+	    }
+
+	    /**
+	    * Se o email digitado já foi adicionado na lista,
+	    * o usuário deve ser avisado e um botão de edição deve ser exibido
+	    */
+	    if(blkAddAtendee.find('label.mail[title="' + newAttendeeEmail + '"]').length) {
+		hasNewAttendee  = false;
+		newAttendeeName = blkAddAtendee.find('label.mail[title="' + newAttendeeEmail + '"]').parents('li').find('label.name').attr('title');
+
+		blkAddAtendee.find('.email-validation').removeClass('hidden')
+		.find('.message label').html("O usuário acima já foi adicionado! <a class=\"small button\">Editar</a>")
+		.find(".button").button().click(function () { 
+		    /**
+		    * Se o usuário optar por editar o participante anteriormente adicionado,
+		    * uma tooltip deve ser aberta para este participante, viabilizando a edição
+		    */
+		    blkAddAtendee.find("ul.attendee-list").scrollTo('label.mail[title="' + newAttendeeEmail + '"]');
+		    /**
+		    * Remove tooltip possivelmente existente
+		    */
+		    if (lastEditAttendeeToolTip.length && lastEditAttendeeToolTip.data('qtip'))
+			lastEditAttendeeToolTip.qtip('destroy');
+
+		    lastEditAttendeeToolTip = blkAddAtendee.find('label.mail[title="' + newAttendeeEmail + '"]').parents('li');
+		    lastEditAttendeeToolTip.qtip({
+			show: {
+			    ready: true, 
+			    solo: true, 
+			    when: {
+				event: 'click'
+			    }
+			},
+		    hide: false,
+		    content: {
+			text: $('<div></div>').html( DataLayer.render( path+'templates/attendee_quick_edit.ejs', {
+			    attendee:{
+				name:newAttendeeName, 
+				mail:newAttendeeEmail
+			    }
+			} ) ), 
+		    title: {
+			text:'Detalhes do participante', 
+			button: '<a class="button close" href="#">close</a>'
+		    }
+		    },
+		    style: {
+			name: 'blue', 
+			tip: {
+			    corner: 'leftMiddle'
+			}, 
+			border: {
+			    width: 4, 
+			    radius: 8
+			}, 
+			width: {
+			    min: 230, 
+			    max:230
+			}
+		    },
+		position: {
+		    corner: {
+			target: 'rightMiddle',
+			tooltip: 'leftMiddle'
+		    },
+		    adjust: {
+			x:0, 
+			y:0
+		    }
+		}
+		});
+	    lastEditAttendeeToolTip.qtip("api").onShow = onShowToolTip;
+	});
+    skipAddNewLine = true;
+    } else {
+	hasNewAttendee  = true;
+	blkAddAtendee.find('.email-validation').addClass('hidden');
+    }
+
+
+    var isExternal = (!!user && !(!!user.isExternal)) ? 0 : 1;
+
+    /**
+    * Remove tooltip possivelmente existente
+    */
+    if (lastEditAttendeeToolTip.length && lastEditAttendeeToolTip.data('qtip'))
+	lastEditAttendeeToolTip.qtip('destroy');
+
+    userId = '';
+    var newAttendeeId = '';
+
+    if (user){
+	if (!skipAddNewLine) {
+	    user[0].id =  DataLayer.put('participant', {
+		user: user[0].id, 
+		isExternal: isExternal, 
+		acl: 'r'
+	    });
+	    user[0].acl = 'r';
+	    user[0].isDirty = !!!objTask.id;
+
+	    blkAddAtendee.find('dd.attendee-list ul.attendee-list').append(
+		DataLayer.render(path+'templates/participants_add_itemlist.ejs', user)
+		)
+	    .scrollTo('max');
+	    callbackAttendee();
+	}
+
+	$(this).val('');
+
+    } else if (!skipAddNewLine) {
+	/**
+	* a) salva como novo usuario externo no banco (apenas com email) e...
+	* adiciona novo contato externo à lista de convidados
+	*/
+
+	userId = DataLayer.put('user', {
+	    name: newAttendeeName, 
+	    mail: newAttendeeEmail, 
+	    isExternal: isExternal
+	});
+	newAttendeeId = DataLayer.put('participant', {
+	    user: userId, 
+	    isExternal: isExternal
+	});
+
+
+	blkAddAtendee.find('dd.attendee-list ul.attendee-list').append(
+	    DataLayer.render(path+'templates/participants_add_itemlist.ejs', [{
+		id:newAttendeeId, 
+		name: newAttendeeName, 
+		mail: newAttendeeEmail, 
+		isExternal: 1, 
+		isDirty: !!!objTask.id
+		}])
+	    ).scrollTo('max');
+	callbackAttendee();
+
+	/** 
+	* Adiciona tootip para atualização dos dados do contato externo
+	* recém adicionado.
+	*/
+	lastEditAttendeeToolTip = blkAddAtendee.find('dd.attendee-list li:last');
+	lastEditAttendeeToolTip.qtip({
+	    show: {
+		ready: true, 
+		solo: true, 
+		when: {
+		    event: 'click'
+		}
+	    },
+	hide: false,
+	content: {
+	    text: $('<div></div>').html( DataLayer.render( path+'templates/attendee_quick_edit.ejs', {
+		attendee:{
+		    name:newAttendeeName, 
+		    mail:newAttendeeEmail
+		}
+	    } ) ), 
+	title: {
+	    text:'Detalhes do participante', 
+	    button: '<a class="button close" href="#">close</a>'
+	}
+	},
+	style: {
+	    name: 'blue', 
+	    tip: {
+		corner: 'leftMiddle'
+	    }, 
+	    border: {
+		width: 4, 
+		radius: 8
+	    }, 
+	    width: {
+		min: 230, 
+		max:230
+	    }
+	},
+    position: {
+	corner: {
+	    target: 'rightMiddle',
+	    tooltip: 'leftMiddle'
+	},
+	adjust: {
+	    x:0, 
+	    y:0
+	}
+    }
+    });
+
+    lastEditAttendeeToolTip.qtip("api").onShow = onShowToolTip;
+
+    $(this).val('');
+
+
+    }
+    event.preventDefault();
+    }
+
+    });
 
     blkAddAtendee.find('.add-attendee-search .ui-icon-search').click(function (task) {
