Archivo de la categoría: R.I.A.

Calendario Multirango en Flex2

Hace algo más de un año trabajábamos en un proyecto que consistía en una aplicación de gestión de reservas para una cadena de hoteles. Una de las opciones necesarias era el mantenimiento de las temporadas de cada hotel, es decir, las tarifas. Aunque pueda parecer algo sencillo y sin importancia, en realidad dista bastante del clásico alta/media/baja. De hecho ni siquiera es algo que permanezca inalterado a lo largo del año, sino que, en función de la demanda y disponibilidad de habitaciones, el propio hotel va modificando las temporadas en función de sus necesidades. La gestión de temporadas se realiza manualmente día a día y para cada uno de los hoteles de la cadena y cambia cada año. Necesitábamos, por tanto, desarrollar un sistema que permitiese administrar las temporadas de manera rápida y sencilla.

La solución que se nos ocurrió fue crear un calendario anual completo, doce DateChooser, uno por cada mes del año, y permitir al administrador configurar en un solo paso el año entero de temporadas. Simplemente seleccionando la temporada que se va a configurar y haciendo click en los días de cada DateChooser se van marcando de un color distinto para cada temporada. Como podéis ver en el ejemplo, es muy sencillo cambiar de temporada los días, seleccionamos otra tarifa y hacemos click en el día que queremos modificar. Es casi tan sencillo cambiar un día como un mes completo.

El problema llegó con el DateChooser puesto que, por defecto, sólo permite seleccionar un día o rango de días, pero siempre marcándolos en el mismo color. Nosotros necesitábamos que de un vistazo el administrador supiese la configuración de las temporadas de su hotel, necesitábamos un código de colores para los fondos de los días, en los números sería poco visual. La solución parte de un componente desarrollado para Flex1.5 hace bastante y que su autor no llegó a portar a Flex2, algo que hicimos nosotros con algunas modificaciones.

Extendiendo el DateChooser

El efecto que queríamos conseguir era colorear el fondo cada día del calendario en función de la tarifa adjudicada, de manera que con un rápido vistazo se tenía claro qué es cada uno.

Lo primero que necesitábamos en nuestro caso particular era ocultar las flechas de navegación de meses, puesto que sólo íbamos a utilizar un mes de cada DateChooser dejando la navegación por años. Por defecto no hay forma de hacerlo ya que estos botones se han definido en mx_internal, así que hemos de recurrir a:

this.mx_internal::fwdMonthButton.visible=false;
this.mx_internal::backMonthButton.visible=false;

En nuestro componente está por defecto, vosotros tendríais que eliminar esas líneas o, mejor, crear un método publico que permita quitarlos.

A continuación definimos el método que haremos público para colorear los días. Como véis en el código, los parámetros son un array con los días a marcar y el color de fondo que le vamos a dar. Tuvimos que implementar un callLater ya que nuestra aplicación, al iniciarse, carga del servidor las temporadas del año en curso y configura los distintos DateChooser, pero nos dimos cuenta que esto se producía antes de que el componente estuviese disponible, con lo cual si intentábamos colorear los días saltaban excepciones de componente no disponible.

Finalmente la función highlight busca los días que se le pasan en el array y configura el color de fondo de cada uno. Dentro del DateChooser, los días son instancias de TextField, pero de nuevo no son accesibles, tenemos que acudir de nuevo a mx_internal. El código es muy explicativo.

public function highlightDays(dayArray:Array, highColor:Number=0xff9900):void{
	var o:CalendarioMultipleColor = this;
	callLater(highlight,[dayArray, highColor]);
}
private function highlight(dayArray:Array, highColor:Number):void {
	if (!dayArray is Array) return;
	if (isNaN(highColor)) highColor = 0xff9900;
	// row 0 of the dateGrid is used for the display of day names
	var startRow:Number = 1;
	// calculate the column where the first day of the month is placed
	var startCol:Number = getOffsetOfMonth(this.displayedYear, this.displayedMonth);
	// how many days do we have this month?
	var lastDay:Number = getNumberOfDaysInMonth(this.displayedYear, this.displayedMonth);
	for (var i:Number = 0; i < dayArray.length; i++) {
		var day:Number = dayArray[i];
		 // only numbers allowed
		if (isNaN(day)) continue;
		if (day < 1) continue;
		if (day > lastDay) continue;
		// calculate row and column of the day
		var row:Number = Math.floor((day-1 + startCol) / 7) + 1;
		var col:Number = (day-1 + startCol) % 7;
		//finally we set background color
		this.mx_internal::dateGrid.mx_internal::dayBlocksArray[col][row].background=true;
		this.mx_internal::dateGrid.mx_internal::dayBlocksArray[col][row].backgroundColor=highColor;
	}
}

Aquí os dejo el ejemplo y código fuente, ya sabéis, botón derecho y View Source.