O novo Spesa está sendo desenvolvido em ritmo acelerado — isso significa que ando trabalhando muito nas minhas horas vagas — e diversas funcionalidades que estou implementando estão sendo extraídas na forma de plugins.

O mais recente deles é o has_calendar, que permite exibir calendários com eventos de maneira muito simples.

A minha idéia, já que não uso Windows nem para desenvolvimento, nem para (sic) produção, foi utilizar o comando cal, disponível em sistemas *nix, evitando toda a complexidade de ter que se trabalhar com datas. Para deixar explicíto, este plugin não irá funcionar no Windows.

Usando o plugin

Primeiro, você terá que instalar o plugin. Para isso, execute o comando script/plugin install git://github.com/fnando/has_calendar.git.

Se você quiser exibir um calendário sem eventos, pode simplesmente chamar o helper calendar.

<%= calendar %>

Se quiser especificar um mês específico, pode passar um hash com algumas opções.

<%= calendar :year => 2008, :month => 9 %>

O dia atual é diferenciado e não exibe o número; em vez disso o texto "TODAY" é colocado no lugar. Se quiser substituir esta mensagem, utilize a opção :today.

<%= calendar :today => 'HOJE' %>

Para adicionar eventos, você deve passar um bloco, que receberá um objeto Date referente ao dia do calendário. Assim, você pode realizar consultas relacionadas a esta data e exibí-las da maneira que achar melhor.

<% calendar do |date| %>
  <% for schedule in Schedule.by_date(date) %>
    <%= link_to schedule.title, schedule_path(schedule) %>
  <% end %>
<% end %>

Como você pode perceber, isso faria até 31 consultas ao banco de dados (uma para cada dia da semana) se você não otimizasse seu código (embora eu tenha escrito o artigo assim para facilitar, minha idéia de uso ia ser totalmente diferente). Pensando nisso após ler o comentário do Carlos, decidi que seria melhor implementar uma forma onde apenas o resultado de uma consulta fosse informado.

No template, você pode definir a opção :events, passando o resultado de sua consulta. O bloco, que antes recebia a data, agora receberá também todos os registros específicos daquele dia.

<% calendar :events => Schedule.all, :field => :scheduled_at do |date, events| %>
  <% for schedule in events %>
    <%= link_to schedule.title, schedule_path(schedule) %>
  <% end %>
<% end %>

Melhorando a apresentação do calendário

Para formatar o calendário, você pode usar este CSS como ponto de partida.

#calendar {
  border-collapse: collapse;
  width: 100%;
}
 
#calendar td,
#calendar th {
  color: #ccc;
  font-family: "Lucida Grande",arial,helvetica,sans-serif;
  font-size: 10px;
  padding: 6px;
}
 
#calendar th {
  border: 1px solid #ccc;
  background: #ccc;
  color: #666;
  text-align: left;
}
 
#calendar td {
  background: #f0f0f0;
  border: 1px solid #ddd;
}
 
#calendar span {
  display: block;
}
 
#calendar td.events {
  background: #fff;
}
 
#calendar td.today {
  background: #ffc;
  color: #666;
}
 
#calendar caption {
  display: none;
}

Ele irá se parecer com isto:

Imagem do has_calendar com estilo CSS

Mais simples, impossível! ;)

NOTA: O Mac OS X não permite iniciar a semana pela segunda-feira. Sendo assim, se você desenvolve neste sistema operacional, a semana começará no domingo. Em sistemas Linux, onde a maioria das aplicações são executadas, a semana iniciará na segunda-feira.

NOTA 2: Se você quiser utilizar este plugin no Windows, certifique-se de que exista um comando cal no seu PATH, retornando exatamente a saída do comando para *nix. Ele deve ser executado no formato cal -m 12 2008. Teoricamente funciona. :)

UPDATE: Este artigo foi atualizado para mostrar a nova opção :events.

UPDATE 2: O Carlos sugeriu adicionar a chamada ao método da data no próprio helper. Claro que fica melhor! Use a opção :field.

Comentários #

#1 Ricardo Duarte disse:
17 Set 08, 10:37AM

Nando,

Fiquei cá a pensar com meus botões: Não será possível definir se a semana iniciará na Seg. ou Dom. através do Locale do Linux?

Quando chegar em casa vou testar isso.

#2 Felipe Gomez disse:
17 Set 08, 12:12PM

Que ÓTIMO saber que vem ai um novo SPESA! :D

#3 Carlos Júnior disse:
17 Set 08, 09:13PM

Excelente plugin Nando! Só tenho uma pequena sugestão. Seria excelente se tivesse uma forma já built-in de fornecer um range de datas ao invés da data atual, assim evita que 30 queries sejão feitas no banco de dados em favor de apenas uma que busca todos os eventos de uma vez.

Abraços!

#4 Ricardo Duarte disse:
17 Set 08, 09:43PM

É... isso que dá opinar sem olhar o source:

cmd << '-m ' unless RUBY_PLATFORM =~ /darwin/

#5 Nando Vieira disse:
18 Set 08, 09:18AM

Carlos, alterei o texto para mostrar como funciona a opção :events. ;)

#6 Abraão disse:
02 Out 08, 04:05PM

Eu sei que tô meio atrasado mas... ao rodar o bloco de eventos eu fico recebendo um retorno dizendo que eu tenho um nilObject... o que não é o caso... alguém passou por isso e achou uma solução? ou isso é uma loucura que acontece só comigo aqui? =)

#7 Nando Vieira disse:
07 Out 08, 04:30PM

Abraão, tem como você publicar o código que gerou o erro?

http://pastie.caboo.se/

Abraço!

#8 Eduardo M. disse:
30 Out 08, 03:29PM

Estou tentando fazer a navegação entre os meses através de links no topo do calendário em seu plugin. O Calendar Helper(http://wiki.rubyonrails.org/rails/pages/Calendar+Helper+Plugin) possui tal recurso na demonstração (http://rubyonrailsworkshops.com/dashboard/2008/10), mas que não foi disponibilizado no source.

Eu fiz a navegação para os meses fora do plugin por métodos Ajax, que controlam as variáveis de mês e ano que são setadas no ":month" e ":year".

Para minha necessidade, fiz a possibilidade de o usuário marcar um evento para si, dentro do calendário, algo como uma agenda.

Como sou iniciante, o código está ruim, e portanto gostaria de sugestões para a navegação (deve ser feita em JavaScript de dentro do Plugin ?)

Agradeço pelo plugin, está sendo de grande ajuda.

#9 Shadow disse:
19 Dez 08, 11:31AM

Fala Nando, fui usar e tive o mesmo problema do Abraão... andei fazendo uns debugs e cheguei na linha que faz o capture (no dia do evento), retorna \n

Colei aqui o código que estou usando:

http://gist.github.com/38017

#10 Guilherme disse:
22 Maio 09, 12:11PM

Olá, preciso utilizar esse plugin no windows. Vi que você deu a dica de funcionamento mas não consegui entender. Dei uma pesquisada e nao encontrei nada também.

Pode dar uma ajuda a respeito da utilização desse plugin no Windows ?

Obrigado

#11 Andrey Viana disse:
23 Jul 09, 09:00AM

Estava precisando exibir esse calendário no windows, então achei um código que vem junto com a instalação do Ruby, nos exemplos dos doc (pelo menos no Windows).

http://pastie.org/556290

Com ele é possível gerar o calendário igual ao do linux no windows, legal né ;-)
Agora vou alterar um pouco o código do plugin pra ver como fazer pra ele funcionar.

Assim que tiver uma solução comento aqui.

Abraços

#12 Andrey Viana disse:
23 Jul 09, 11:00AM

ainda nao tive tempo pra testar, mas acho que esse eh o código:

begin
cmd = 'cal '
cmd << '-m ' unless RUBY_PLATFORM =~ /darwin/
rescue
cmd = "ruby lib/utils/cal.rb -c os "
end

* esse codigo fica no lugar do:
cmd = 'cal '
cmd << '-m ' unless RUBY_PLATFORM =~ /darwin/

* tem que colocar o cal.rb na pasta lib/utils

abraços

#13 Marcio Migueis disse:
18 Ago 09, 11:23AM

Eu preciso criar a table Schedule ? Quais os campos dela ? Não tem um já "pronto "?

Obrigado.

#14 João disse:
08 Jun 10, 01:54PM

Boa tarde,
precisava saber duas coisas. O eu posso formatar o has_calendar pra ficar só aparecendo a quarta-feira? E outra, tem como passar as informações de data para outra página com algum método?

#15 Douglas André disse:
10 Jun 10, 01:28PM

Olá Fernando,
estava utilizando com êxito o has_calendar com a versão antiga do ubuntu (9.10), entretanto quando realizei a atualização do sistema operacional (Ubuntu 10.04) o calendário parou de funcionar. Acredito que seja devido a diferença de patchlevel do Ruby (174 para 249). Gostaria de saber se apenas eu tive essa experiência e se você sabe um possível motivo para o problema.
O erro referencia uma data inválida, na criação de uma data, cujo dia deveria ser um int mas por algum motivo passa uma string.
Abraço

#16 Nando Vieira disse:
10 Jun 10, 11:24PM

Fala Douglas! Você foi o primeiro a reclamar disso. Abre um ticket no Github com output de `cal -m`. Abraço!

Deixe um comentário





Não é aceito código HTML: adicione-o no pastie.org ou paste.milk-it.net e poste apenas o link.

Se este é seu primeiro comentário, ele terá que ser aprovado antes de ser exibido.

JavaScript Avançado

O JavaScript é a única linguagem que muitos acreditam saber sem nunca terem parado para realmente aprendê-la. Neste workshop rápido você entenderá de verdade todos os conceitos avançados do JavaScript em 4 horas puramente práticas.

Saiba mais Fechar

Conheça também o HOWTO