Arquivo

Arquivo da Categoria ‘jQuery’

Solução para ‘bug’ de Horário de Verão (Daylight Saving)

1, novembro, 2010 admin Sem comentários

Ao som de: Audioslave – Original Fire ♫

Fala galera, depois de quase 1 ano sem passar por aqui, dessa vez não por falta de tempo e sim por um pouco de preguiça confesso, venho trazer a vocês uma possivel solução para um problema que passei na empresa onde trabalho. Trago a solução

Problema: Ao utilizar o componente CalendarExtender so .net (configurado para apresentar em pt-BR) não é possivel selecionar a data 17/10/2010 (ou qualquer outra data que sejá ‘virada’ de horário de verão), onde ao selecionar o dia 17 ele automaticamente apresentava dia 16 e se inserir manualmente dia 17 o componente retorna como uma ‘Data Inválida”.

Causa: No Brasil o horário de verão entra em vigor à meia noite, adiantando assim o relógio para 1h da manhã, nosso GMT é -3 e no horário de verão -2, o que acontece, é que como à meia noite ele automaticamente vai para 1h a hora “17/10/2010 00:00:00″ passa a não mais existir, o problema não é o GMT, o problema é que não dá para configurar a função getDate() do javascript (imbutido no Calendar Extender).

Tentativa de solução: Tentar interceptar no global.asax ao solicitar uma data ao .net adicionar 1 hora, assim o “limbo da meia noite” seria contornado. Achei muitas dificuldades em conseguir ‘setar’ essa 1 hora, todos os métodos e propriedades referentes a Daylight Saving são apenas get e não é possivel modificar o getDate() utilizado.

Foi aí que lembrei que em um dos meus projetos pessoais utilizei jQuery para apresentar um calendário ao usuário, chama-se Date Picker, para utiliza-lo basta adicionar em seu formulário a API jQuery UI, é um componente totalmente personalizavel. Porém, pensando no conceito de reutilização de código criei um UserControl onde já é adicionado todas as referências de Javascript cabendo apenas referenciar o CSS nas páginas. Isso porque se eu adicionar o CSS no controle, a cada chamada do controle será colocado uma tag <link..>.

Criei um novo website (C#) utilizado o MS Visual Studio 2010, nomeei de DatePickerTest, modifiquei o web.config para poder utilizar alguns recursos do MS AjaxToolkit, criei uma pasta chamada dll, coloquei minha dll do toolkit e referenciei no projeto (o post não é para aprender a utilizar o toolkit então não entrarei muito em detalhes nesse post. No final colocarei um link com todo projeto configurado e funcionando).

Criei uma nova pasta chamada Controls, que será onde colocaremos os controles do projeto (tenho mania de organização), dentro dela adicionei um novo UserControl chamado DateBox.ascx

DateBox.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="DateBox.ascx.cs" Inherits="DatePickerTest.Controls.DateBox" %>
<asp:ScriptManagerProxy ID="sm" runat="server" ClientIDMode="Predictable" />
<asp:TextBox runat="server" ClientIDMode="Predictable" ID="dateTextBox" Width="70px" MaxLength="10" />
<asp:RequiredFieldValidator ID="required" runat="server" ClientIDMode="Predictable" ControlToValidate="dateTextBox" ErrorMessage="Campo obrigatório" Display="None" Enabled="false" />
<asp:ValidatorCalloutExtender ID="ValCallExtRequired" TargetControlID="required" runat="server" ClientIDMode="Predictable" HighlightCssClass="ReqWarn" />
<asp:CustomValidator runat="server" ID="CustomVal" ControlToValidate="dateTextBox" ClientValidationFunction="validateDate" Display="None" EnableClientScript="true" ErrorMessage="Data inválida." ClientIDMode="Predictable" HighlightCssClass="ReqWarn" />
<asp:ValidatorCalloutExtender ID="ValidatorCalloutExtender1" TargetControlID="CustomVal" runat="server" ClientIDMode="Predictable" HighlightCssClass="ReqWarn" />

DateBox.ascx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace DatePickerTest.Controls
{
[ValidationProperty("Date")]
public partial class DateBox : UserControl
{
protected void Page_Init(object sender, EventArgs e)
{
sm.Scripts.Add(new ScriptReference("~/scripts/jquery-1.3.2.js"));
sm.Scripts.Add(new ScriptReference("~/scripts/jquery.ui.core.js"));
sm.Scripts.Add(new ScriptReference("~/scripts/jquery.ui.datepicker.js"));
sm.Scripts.Add(new ScriptReference("~/scripts/util.js"));
}

protected void Page_PreRender(object sender, EventArgs e)
{
string script = @"$(function () {
$('#" + dateTextBox.ClientID + @"').datepicker({
showButtonPanel: true,
currentText: 'Hoje',
duration: 100,
dateFormat: 'dd/mm/yy',
showOn: 'button',
buttonImage: '/mapfrecap/img/calendario.gif',
buttonImageOnly: true,
dayNames: ['Domingo', 'Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado', 'Domingo'],
dayNamesMin: ['D', 'S', 'T', 'Q', 'Q', 'S', 'S', 'D'],
dayNamesShort: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb', 'Dom'],
monthNames: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'],
monthNamesShort: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'],
nextText: 'Próximo',
prevText: 'Anterior',
closeText: 'Fechar',
buttonText: 'Calendário',
showOtherMonths: true,
selectOtherMonths: true
});";
if (!Enabled)
script += "$('#" + dateTextBox.ClientID + @"').datepicker('disable');";
script += @"});";

ScriptManager.RegisterStartupScript(this, typeof(DateBox), "initDateBox" + dateTextBox.ClientID, script, true);
}
public DateTime? Date
{
get
{
return dateTextBox.Text != string.Empty ? (DateTime?)DateTime.Parse(dateTextBox.Text) : null;
}
set
{
dateTextBox.Text = value.Value.ToString("d");
}
}

public String ValidationGroup
{
get { return required.ValidationGroup; }
set { required.ValidationGroup = value; CustomVal.ValidationGroup = value; }
}

public bool Required
{
get { return required.Enabled; }
set { required.Enabled = value; }
}

public bool Enabled { get { return dateTextBox.Enabled; } set { dateTextBox.Enabled = value; } }
public bool ReadOnly { get { return dateTextBox.ReadOnly; } set { dateTextBox.ReadOnly = value; } }

public event EventHandler TextChanged { add { dateTextBox.TextChanged += value; } remove { dateTextBox.TextChanged -= value; } }
public bool AutoPostBack
{
get { return dateTextBox.AutoPostBack; }
set { dateTextBox.AutoPostBack = value; }
}

public override string ClientID
{
get
{
return dateTextBox.ClientID;
}
}
}
}

Até aqui o componente está finalizado, com algumas particularidades que eu mesmo implementei, como uma validação de o campo será obrigatório ou nao (Required), se o componente estará ativo ou nao (Enabled), propriedade de AutoPostBack, ValidationGroup, etc. Caso surja dúvidas sobre o código “[ValidationProperty("Date")]” explico aqui… Esse código é para ‘expor’ o valor de Date (que é onde fica armazenado o valor selecionado pelo calendário) à pagina que irá utiliza-lo, podendo assim fazer validações com CompareValidator.

No nosso DateBox.ascx temos um ClientValidationFunction=”validateDate”, essa é a função javascript que eu fiz para validar a data do nosso calendário, é aqui que contornamos o problema de horario de verão, dentro da nossa pasta ‘scripts’ teremos um arquivo chamado ‘util.js’ com o seguinte conteúdo:

util.js

function validateDate(oSrc, args) {
var iDay, iMonth, iYear;
var arrValues;
arrValues = args.Value.split("/");
iDay = arrValues[0];
iMonth = arrValues[1];
iYear = arrValues[2];

var testDate = new Date(iYear, iMonth - 1, iDay, 4, 0, 0, 0);
if ((testDate.getDate() != iDay) ||
(testDate.getMonth() != iMonth - 1) ||
(testDate.getFullYear() != iYear)) {
args.IsValid = false;
return;
}

return true;
}

O que nos importa nessa validação é parte em negrito => var testDate = new Date(iYear, iMonth – 1, iDay, 4, 0, 0, 0);
Ali estamos adicionando 4 horas à data selecionada, eliminando assim o “limbo” da meia noite não existente, como só queremos mesmo é a Data e nao o horário, isso resolve nosso problema. Tudo isso porque não conseguimos sobrescrever a função de getDate() do CalendarExtender.

Agora um pequeno exemplo do como utiliza-lo:

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="DatePickerTest.Default" %>

<%@ Register Src="~/Controls/DateBox.ascx" TagName="DateBox" TagPrefix="uc" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<link rel="stylesheet" href="~/styles/jquery-ui-1.7.3.custom.css" type="text/css" media="screen" runat="server" />
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="sm" runat="server" />
<div>
<uc:DateBox runat="server" ID="edtData" />
</div>
</form>
</body>
</html>

Simple não? Só precisamos fazer 3 coisas:

1 – Registrar o componente => <%@ Register Src=”~/Controls/DateBox.ascx” TagName=”DateBox” TagPrefix=”uc” %>
2 – Adicionar o CSS (pelo motivo dito na introdução do post)
3 – Adicionar o componente onde você precisar => <uc:DateBox runat=”server” ID=”edtData” />

Para obter o valor pelo seu CS é só utilizar ‘nomeComponente.Date’ como é um nullable em alguns casos você pode precisar utilizar um .Value (nomeComponente.Date).
Galera, espero que todos tenham entendido, caso contrario só comentar dizendo qual linha não entendeu que eu tiro as dúvidas, e em casos de erro especificar exatamente o erro, com linha e o código da linha para que fique mais facil de ajudar. Abaixo o projeto com nosso DateBox funcionando pra quem quiser, não coloquei online pois minha hospedagem é PHP =/

Baixar projeto de exemplo

Grande abraço, até a próxima.

VN:F [1.9.5_1105]
Rating: 5.0/5 (3 votes cast)
VN:F [1.9.5_1105]
Rating: +3 (from 3 votes)

Post to Twitter . Post to Delicious . Post to Digg . Post to Facebook . Post to MySpace .

Ordenando Tabelas com jQuery

12, outubro, 2009 Leandro Barral Sem comentários

Venho hoje quase fim de feriado postar um plugin que achei muito interessante, e fácil de usar, diga-se de passagem. Se chama TableSorter, ele nada mais faz do que ordenar sua tabela conforme quiser, o mais legal é que ele suporta paginação e tem como ordenar mais de uma coluna ao mesmo tempo, aqui vou postar o básico e pra quem tiver dificuldade em entender a documentação (em inglês) posta um comentário que eu coloco exemplos mais “bem elaborados”, pois bem, tenha certeza que tem o jQuery linkado em sua páginae que tenha baixado a versão mais recente do plugin com um dos “temas” disponiveis (azul e verde). Linkado todos os arquivos (jquery, tablesorter e os css do tema) vamos para os códigos.
Vamos tomar base em uma tabela com thead e tbody (padrão w3c para criação de tabelas) com o seguinte conteúdo:

<table id="TabelaOrdenada">
<thead>
<tr>
<th>Primeiro Nome</th>
<th>Último Nome</th>
<th>Email</th>
<th>Profissão</th>
<th>Site</th>
</tr>
</thead>
<tbody>
<tr>
<td>Leandro</td>
<td>Barral</td>
<td>webmaster@leandrobarral.com.br</td>
<td>Controlador Operacional</td>
<td>http://blog.leandrobarral.com.br</td>
</tr>
<tr>
<td>José</td>
<td>Benedito</td>
<td>jbenedito@yahoo.com.br</td>
<td>Auxiliar Geral</td>
<td>N/D</td>
</tr>
<tr>
<td>Maria</td>
<td>João</td>
<td>maju@hotmail.com</td>
<td>Dona de Casa</td>
<td>http://www.orkut.com/meu-id-do-orkut</td>
</tr>
<tr>
<td>Karine</td>
<td>Natali</td>
<td>ka.natali@gmail.com</td>
<td>Auxiliar de Classe</td>
<td>http://www.saborcereja.co.cc</td>
</tr>
</tbody>
</table>

Até aqui apenas uma tabela, com os nomes fora de ordem e tal, agora vem o plugin que nada mais é que:

$(document).ready(function() // quando estiver carregado faça...
{
$("#TabelaOrdenada").tablesorter(); // inicia o plugin, e... só!
}
)

Somente isso! Se quiserem ordenar por mais de um parametro segure shift e clique nas colunas desejadas. O plugin aceita vários muitos outros parametros, como iniciar com uma ou algumas colunas ordenadas, pegar resultados via requisições ajax e colocar na tabela, habilitar ordenar somente as colunas que quiser, etc…
Espero que tenham gostado, qualquer dúvida só postar um comentário que ajudarei com certeza.

Links úteis:
Link Oficial do Projeto
Site do Criador
Demonstrações Online

Até a próxima! E tenham todos um ótimo final de feriado!

VN:F [1.9.5_1105]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.5_1105]
Rating: +1 (from 1 vote)

Post to Twitter . Post to Delicious . Post to Digg . Post to Facebook . Post to MySpace .