Per un piccolo gestionale medico ultimamente mi è capitato sotto mano
FullCalendar, un ottimo calendario jQuery "full-size" altamente configurabile. Già dalla home page di questo progetto emergono i punti forti del plugin: eventi di tutto il giorno o schedulati, drag & drop degli eventi, viste per mese, per settimana e vista giornaliera. Il progetto è molto ben documentato, quindi per un utilizzo base rimando ogni spiegazione al sito.
Voglio pubblicare però la configurazione che ho utilizzato, cercando di mostrarne le potenzialità:
$('#calendar_strutture').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month' //,agendaWeek,agendaDay
},
firstHour: 6,
firstDay: 1,
allDaySlot : false,
timeFormat: 'HH:mm',
monthNames:['Gennaio','Febbraio','Marzo','Aprile','Maggio','Giugno','Luglio','Agosto','Settembre','Ottobre','Novembre','Dicembre'],
monthNamesShort: ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'],
dayNames: ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'],
dayNamesShort: ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'],
buttonText: {
prev: ' ◄ ', // left triangle
next: ' ► ', // right triangle
prevYear: ' << ', // <<
nextYear: ' << ', // >>
today: 'Oggi',
month: 'Mese',
week: 'Settimana',
day: 'Giorno'
},
columnFormat: {
month: 'ddd', // Mon
week: 'd/M ddd', // Mon 9/7
day: 'dddd d/M' // Monday 9/7
},
editable: true,
events: {
url: 'lista_calendario_strutture.php',
cache: true,
//color: 'purple', // a non-ajax option
textColor: 'white' // a non-ajax option
},
lazyFetching: false,
eventClick: function(calEvent) {
if(confirm("Elimino dal calendario la disponibilita' della struttura per il giorno selezionato?")) {
$.ajax({
url: "interventi.php?section=calendario_strutture&action=delete",
type: 'POST',
data: {
struttura: calEvent.title,
data: calEvent.start.getTime()
},
success: function(msg){
//alert(msg); //debug
$('#calendar_strutture').fullCalendar('removeEvents',calEvent.id);
},
error: function() {
revertFunc();
}
});
}
},
eventMouseover: function(calEvent) {
$(this).find('.fc-event-title').html('<img src="template/default/admin/assets/images/delete.png" /> '+calEvent.title);
},
eventMouseout: function(calEvent) {
$(this).find('.fc-event-title').html(calEvent.title);
},
eventDrop: function(calEvent,dayDelta,minuteDelta,allDay,revertFunc) {
//Qui ajax per spostamento evento
$.ajax({
url: "interventi.php?section=calendario_strutture&action=move",
type: 'POST',
data: {
struttura: calEvent.title,
movimento: dayDelta,
nuova_data: calEvent.start.getTime()
},
success: function(msg){
//alert(msg);
},
error: function() {
revertFunc();
}
});
},
droppable: true,
drop: function(date, allDay) { // this function is called when something is dropped
// retrieve the dropped element's stored Event Object
var originalEventObject = $(this).data('eventObject');
// we need to copy it, so that multiple events don't have a reference to the same object
var copiedEventObject = $.extend({}, originalEventObject);
var today = new Date();
// assign it the date that was reported
copiedEventObject.id = today.getTime();
copiedEventObject.start = date;
copiedEventObject.allDay = allDay;
//alert(copiedEventObject.title + ' ' + copiedEventObject.start.getTime());
//Qui ajax per inserimento disponibilita in calendario struttura
$.ajax({
url: "interventi.php?section=calendario_strutture&action=insert",
type: 'POST',
data: {
struttura: copiedEventObject.title,
data: copiedEventObject.start.getTime()
},
success: function(msg){
//alert(msg); //debug
// render the event on the calendar
$('#calendar_strutture').fullCalendar('renderEvent', copiedEventObject, false);
}
});
}
});
$('#external-events div.external-event').each(function() {
// create an Event Object (http://arshaw.com/fullcalendar/docs/event_data/Event_Object/)
// it doesn't need to have a start or end
var eventObject = {
title: $.trim($(this).text()), // use the element's text as the event title
backgroundColor: $(this).css('background-color')
};
// store the Event Object in the DOM element so we can get to it later
$(this).data('eventObject', eventObject);
// make the event draggable using jQuery UI
$(this).draggable({
zIndex: 999,
revert: true, // will cause the event to go back to its
revertDuration: 0 // original position after the drag
});
});
Questa prima parte, che deve essere contenuta nella parte relativa a
$(document).ready(...), specifica il comportamento del calendario, in particolare:
- deve poter gestire, tramite chiamate ajax, lo spostamento degli eventi (eventDrop), che in questo caso particolare, sono "disponibilità" delle sale operatorie in determinate strutture ospedaliere
- deve gestire l'eliminazione delle disponibilità, mediante click del mouse (eventClick) sull'evento stesso (notare che quando il mouse si trova sopra l'evento viene mostrata una icona "cestino")
- deve gestire la creazione delle disponibilità mediante il trascinamento dall'elenco strutture sulla sinistra al calendario (drop), date una occhiata allo screenshot per capire di cosa sto parlando
- La parte finale del codice jQuery è relativa al punto 3, fa capire al motore javascript che i
sulla sinistra deve gestirli come "draggable" e creare un oggetto evento (Event Object) in modo da poterlo poi gestire in FullCalendar.
Di seguito il codice html utilizzato (elenco strutture + calendario):
<div id='wrap' style="width:100%;margin: 0 auto;">
<div id='external-events' style="float: left;width: 150px;padding: 0 10px;border: 1px solid #ccc;background: #eee;text-align: left;margin-right:20px;">
<h4>Elenco Strutture</h4>
<div class='external-event' style="background-color:#0099FF">Struttura Ospedaliera 1</div>
<div class='external-event' style="background-color:#996699">Struttura Ospedaliera 2</div>
</div>
<div id='calendar_strutture' style="width: 900px;float:left;"></div>
<div style='clear:both'></div>
</div>
</div>
Il risultato finale!