Jeg har søgt forgæves rundt på nettet efter en JavaScript kalender. Altså ikke en date-picker, men en lille kalender, hvor man kan se en måned ad gangen, og lade brugeren bladre rundt. Man skal kunne tilføje highlighte datoer, og helst kun for en måned ad gangen – Ajax kald ved månedskifte, og så skal de markerede datoer helst have en klik-event, som jeg kan hooke op på. Ikke en stor vulgær scheduler server kontrol, men bare en lille script-kontrol – en widget.
Jeg har søgt rundt, men har ikke fundet noget der passer mit behov, så der er jo ikke andet at gøre, end at smøge ærmerne op, og scripte en fra bunden…
Det vil være ret omfattende at beskrive udviklingen af en kalender widget, men jeg vil gerne lige gøre opmærksom på et par udfordringer man løber ind i, når man udvikler en sådan.
Udfordring 1: Min dato iterator fungerer ikke den 25. oktober
Jeg har lavet en extension til Date objektet, der implementerer addDays metoden:
Date.prototype.addDays = function(days) {
return new Date(this.getTime() + (1000 * 60 * 60 * 24 * days));
};
Den bruger jeg i en for-next-løkke, men oplever at den 25. oktober kommer dobbelt ud. Der er selvfølgelig tale om et problem i forbindelse med overgangen til sommertid, og det faktum at jeg føjer millisekunder til datoen, og ikke dage. I .Net, er vi vandt til at AddDays, føjer dage til, og fixer sommer-/vintertids problemet for os. Det bør min extension også gøre. Jeg udnytter at setDate virker, således at den opdaterer måneden, når man sætter et tal der er større end antallet af dage i måneden.
Date.prototype.addDays = function(days) {
var result = new Date(this.valueOf());
result.setDate(result.getDate() + days);
return result;
};
Udfordring 2: Udlæsning af ugenumere
I alle kalendere skal der jo være en kolonne med ugenummer – det er i hvert tilfælde uundværligt i danmark. ISO 8601 definerer uge numrene som følgende:
- Ugen starter med mandag
- Uge 1 er den uge der indeholder den første torsdag
- Årets sidste uge er den uge der indeholder årets sidste torsdag
En implementering, skal altså tage udgangspunkt i torsdagen i den uge man befinder sig i (husk at søndag er sidste dag i ugen, og ikke den første som Date objektet håndterer det).
var IsoDayOfWeek = date.getDay()==0? 7: date.getDay(); // Søndag = 7
date.setDate( date.getDate() + 4 - IsoDayOfWeek ); // Ændre til nærmeste torsdag
Nu mangler vi blot at finde torsdagens dag-i-år værdi, og det gøres nemmest ved at regne med millisekunder. Altså: Antallet af millisekunder (ms) for datoen - (minus) antallet af ms for 1. januar i året - divideret med 86400000 ms. Altså:
var DayOfYear = ( date.getTime() - Date.UTC( date.getFullYear(), 0, 1 )) / 864e5;
Så er vi lige ved at være der - vi mangler blot at dividerer med 7 dage; runde ned, og lægge 1 dag til:
var week = Math.floor( DayOfYear / 7 ) + 1;
Thats it - hele koden for vores 'besværlige' funktion, er herefter følgende:
Date.prototype.getWeek = function() {
var refDate = new Date(this.valueOf());
var IsoDayOfWeek = refDate.getDay() == 0 ? 7 : refDate.getDay(); // Søndag = 7
refDate.setDate(refDate.getDate() + 4 - IsoDayOfWeek); // Ændre til nærmeste torsdag
var DayOfYear = (refDate.getTime() - Date.UTC(date.getFullYear(), 0, 1)) / 864e5;
var week = Math.floor(DayOfYear / 7) + 1;
return week;
};
Ud over det, var en kalenderimplementering ret meget lige ud af landevejen, og du er velkommen til at downloade og bruge den selv.
Husk at give mig et praj, hvis du finder fejl, eller laver forbedringer.
Code on…