El calendario jQuery necesita una pequeña utilidad para moverse entre distintos meses y poder ver cualquier mes de cualquier año.
De paso, veremos cómo agregar un control para cerrar la ventana del calendario con un pequeño efectillo que jQuery hará por nosotros.
A lo largo de este artículo conseguiremos llegar a este estado del desarrollo del calendario.
Layout del calendario actualizado
Igual que hicimos para empezar a crear el calendario, hemos realizado primero la maquetación de los controles que vamos a incorporar en este artículo.El nuevo layout del calendario incluye el nombre de mes, un botón para ir al mes siguiente y anterior y el botón para ocultar el componente.
Contol para cerrar el calendario
De entre todos los nuevos controles que estamos colocando a este calendario, el más básico es el que sirve para cerrar la capa para la selección de fechas. Es un simple enlace-botón que tiene un evento clic asociado que oculta la capa del calendario.
//control para ocultar el calendario
var botonCerrar = $('<a href="#" class="calencerrar"><span></span></a>');
botonCerrar.click(function(e){
e.preventDefault();
calendario.hide("slow");
})
var capaCerrar = $('<div class="capacerrar"></div>');
capaCerrar.append(botonCerrar)
Controles para mes siguiente y anterior
Hemos definido un par de controles para navegar a los meses siguiente y anterior. Son parecidos al control de cerrar, con la particularidad que en el evento clic actualizan las variables locales al plugin mes y año, para trasladarse al siguiente o al anterior. Luego llama a una función que veremos dentro de poco, llamada muestraDiasMes(), para actualizar las capas con los días del mes.
//controles para ir al mes siguiente / anterior
var botonMesSiguiente = $('<a href="#" class="botonmessiguiente"><span></span></a>');
botonMesSiguiente.click(function(e){
e.preventDefault();
mes = (mes + 1) % 12;
if (mes==0)
ano++;
capaDiasMes.empty();
muestraDiasMes(mes, ano);
})
var botonMesAnterior = $('<a href="#" class="botonmesanterior"><span></span></a>');
botonMesAnterior.click(function(e){
e.preventDefault();
mes = (mes - 1);
if (mes==-1){
ano--;
mes = 11
}
capaDiasMes.empty();
muestraDiasMes(mes, ano);
})
Esos dos botones, igual que el botón para cerrar la capa, deben añadirse a la capa del calendario, con funciones append() que veremos en el código completo del plugin.
Función para mostrar los días
Hasta ahora el calendario sólo mostraba el mes y año actuales y no se podía cambiar a no ser que se modificase la hora del sistema operativo. En este paso tenemos que mostrar los días de cualquier mes y año en el calendario, ya que vamos a tener que navegar entre distintos meses y años para seleccionar una fecha.Por ello hemos separado el código que sirve para la generación de los días a una función aparte. Esa función recibirá los parámetros de mes y año del calendario a mostrar y calculará los días disponibles en ese mes y mostrará las capas correspondientes.
Esta función se llamará muestraDiasMes() y la veremos a continuación en el código completo del plugin.
Código completo del plugin
El código de nuestro plugin para la selección de fechas se puede ver a continuación. Aun le faltan varias cosas, pero ya se ve mucho más dinámico con las opciones para navegar por los meses.
jQuery.fn.calendarioDW = function() {
this.each(function(){
//saber si estoy mostrando el calendario
var mostrando = false;
//variable con el calendario
var calendario;
//variable con los días del mes
var capaDiasMes;
//variable para mostrar el mes y ano que se está viendo
var capaTextoMesAnoActual = $('<div class="mesyano"></div>');
//iniciales de los días de la semana
var dias = ["l", "m", "x", "j", "v", "s", "d"];
//nombres de los meses
var nombresMes = ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"]
//elemento input
var elem = $(this);
//creo un enlace-botón para activar el calendario
var boton = $("<a class='botoncal' href='#'><span></span></a>");
//inserto el enlace-botón después del campo input
elem.after(boton);
//evento para clic en el botón
boton.click(function(e){
e.preventDefault();
mostrarCalendario();
});
//evento para clic en el campo
elem.click(function(e){
this.blur();
mostrarCalendario();
});
//función para mostrar el calendario
function mostrarCalendario(){
if(!mostrando){
mostrando = true;
//es que hay que mostrar el calendario
//dias de la semana
var capaDiasSemana = $('<div class="diassemana"></div>');
$(dias).each(function(indice, valor){
var codigoInsertar = '<span';
if (indice==0){
codigoInsertar += ' class="primero"';
}
if (indice==6){
codigoInsertar += ' class="domingo ultimo"';
}
codigoInsertar += ">" + valor + '</span>';
capaDiasSemana.append(codigoInsertar);
});
//capa con los días del mes
capaDiasMes = $('<div class="diasmes"></div>');
//un objeto de la clase date para calculo de fechas
var objFecha = new Date()
//mes y año actuales
var mes = objFecha.getMonth();
var ano = objFecha.getFullYear();
//muestro los días del mes y año dados
muestraDiasMes(mes, ano);
//control para ocultar el calendario
var botonCerrar = $('<a href="#" class="calencerrar"><span></span></a>');
botonCerrar.click(function(e){
e.preventDefault();
calendario.hide("slow");
})
var capaCerrar = $('<div class="capacerrar"></div>');
capaCerrar.append(botonCerrar)
//controles para ir al mes siguiente / anterior
var botonMesSiguiente = $('<a href="#" class="botonmessiguiente"><span></span></a>');
botonMesSiguiente.click(function(e){
e.preventDefault();
mes = (mes + 1) % 12;
if (mes==0)
ano++;
capaDiasMes.empty();
muestraDiasMes(mes, ano);
})
var botonMesAnterior = $('<a href="#" class="botonmesanterior"><span></span></a>');
botonMesAnterior.click(function(e){
e.preventDefault();
mes = (mes - 1);
if (mes==-1){
ano--;
mes = 11
}
capaDiasMes.empty();
muestraDiasMes(mes, ano);
})
//capa para mostrar el texto del mes y ano actual
var capaTextoMesAno = $('<div class="textomesano"></div>');
capaTextoMesAno.append(botonMesSiguiente);
capaTextoMesAno.append(botonMesAnterior);
capaTextoMesAno.append(capaTextoMesAnoActual);
//calendario y el borde
calendario = $('<div class="capacalendario"></div>');
var calendarioBorde = $('<div class="capacalendarioborde"></div>');
calendario.append(calendarioBorde);
calendarioBorde.append(capaCerrar);
calendarioBorde.append(capaTextoMesAno);
calendarioBorde.append(capaDiasSemana);
calendarioBorde.append(capaDiasMes);
//inserto el calendario en el documento
$(document.body).append(calendario);
//lo posiciono con respecto al boton
calendario.css({
top: boton.offset().top + "px",
left: (boton.offset().left + 20) + "px"
})
//muestro el calendario
calendario.show("slow");
}else{
//es que el calendario ya se estaba mostrando...
calendario.fadeOut("fast");
calendario.fadeIn("fast");
}
}
function muestraDiasMes(mes, ano){
//muestro en la capaTextoMesAno el mes y ano que voy a dibujar
capaTextoMesAnoActual.text(nombresMes[mes] + " " + ano);
//muestro los días del mes
var contadorDias = 1;
//calculo la fecha del primer día de este mes
var primerDia = calculaNumeroDiaSemana(1, mes, ano);
//calculo el último día del mes
var ultimoDiaMes = ultimoDia(mes,ano);
//escribo la primera fila de la semana
for (var i=0; i<7; i++){
if (i < primerDia){
//si el dia de la semana i es menor que el numero del primer dia de la semana no pongo nada en la celda
var codigoDia = '<span class="diainvalido';
if (i == 0)
codigoDia += " primero";
codigoDia += '"></span>';
} else {
var codigoDia = '<span';
if (i == 0)
codigoDia += ' class="primero"';
if (i == 6)
codigoDia += ' class="ultimo domingo"';
codigoDia += '>' + contadorDias + '</span>';
contadorDias++;
}
var diaActual = $(codigoDia);
capaDiasMes.append(diaActual);
}
//recorro todos los demás días hasta el final del mes
var diaActualSemana = 1;
while (contadorDias <= ultimoDiaMes){
var codigoDia = '<span';
//si estamos a principio de la semana escribo la clase primero
if (diaActualSemana % 7 == 1)
codigoDia += ' class="primero"';
//si estamos al final de la semana es domingo y ultimo dia
if (diaActualSemana % 7 == 0)
codigoDia += ' class="domingo ultimo"';
codigoDia += '>' + contadorDias + '</span>';
contadorDias++;
diaActualSemana++;
var diaActual = $(codigoDia);
capaDiasMes.append(diaActual);
}
//compruebo que celdas me faltan por escribir vacias de la última semana del mes
diaActualSemana--;
if (diaActualSemana%7!=0){
//console.log("dia actual semana ", diaActualSemana, " -- %7=", diaActualSemana%7)
for (var i=(diaActualSemana%7)+1; i<=7; i++){
var codigoDia = '<span class="diainvalido';
if (i==7)
codigoDia += ' ultimo'
codigoDia += '"></span>';
var diaActual = $(codigoDia);
capaDiasMes.append(diaActual);
}
}
}
//función para calcular el número de un día de la semana
function calculaNumeroDiaSemana(dia,mes,ano){
var objFecha = new Date(ano, mes, dia);
var numDia = objFecha.getDay();
if (numDia == 0)
numDia = 6;
else
numDia--;
return numDia;
}
//función para ver si una fecha es correcta
function checkdate ( m, d, y ) {
// función por http://kevin.vanzonneveld.net
// extraida de las librerías phpjs.org manual en http://www.desarrolloweb.com/manuales/manual-librerias-phpjs.html
return m > 0 && m < 13 && y > 0 && y < 32768 && d > 0 && d <= (new Date(y, m, 0)).getDate();
}
//funcion que devuelve el último día de un mes y año dados
function ultimoDia(mes,ano){
var ultimo_dia=28;
while (checkdate(mes+1,ultimo_dia + 1,ano)){
ultimo_dia++;
}
return ultimo_dia;
}
});
return this;
};
Podemos ver el ejemplo en marcha, tal como ha quedado con estas modificaciones.
En el siguiente artículo nos aproximaremos bastante a la finalización del calendario, haciendo que los números de los días sean seleccionables, con lo que nuestro componente ya funcionará como lo que se conoce como datepicker.
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...