Interaktiver Kalender

von Thomas Salvador.

Zum Abschluß der Betrachtungen von Datum und Zeit mit JavaScript noch ein Script, welches einen Kalender darstellt.

Was brauchen wir für einen Kalender?

Planung

Zum einen brauchen wir Steuerelemente. Wir beschränken uns dabei auf Elemente für vorheriges bzw. nächstes Jahr bzw. Monat. Diese Elemente fassen wir zu einem Formular "control" zusammen.

Zum anderen brauchen wir freilich Elemente, in denen wir den Kalender selbst darstellen. Wir verwenden auch hierfür Buttons, die wir in einer 6x7 Matrix anordnen. Um dies halbwegs ordentlich formatiert hinzubekommen, setzt man das Ganze einfach als Tabelle. Diese Tabelle umfassen wir mit einem Formular "cal".

Man macht sich leicht klar, dass man die Matrix selbst effektiv in JavaScript implementieren kann. Dies ist erheblich effizienter und zudem platzsparender, als sie direkt zu setzen.

Schließlich stellen wir "control" und "cal" mit Hilfe einer Tabelle übereinander, so dass wir ein recht hübsches Aussehen erreichen.

Implementierung

Gut, das implementieren wir erstmal.

Implementierung der Schnittstelle

Nach Meinung des Autors sollte man bei massiverem JavaScript-Einsatz Benutzer nicht JavaScript-fähiger Browser entsprechend informieren, damit sich diese nicht wundern, warum gar nichts funktioniert.

<noscript>
Ihr Browser unterst&uuml;tzt JavaScript nicht, oder die Unterst&uuml;tzung
ist abgeschaltet. So k&ouml;nnen Sie diesen Kalender leider nicht benutzen.
</noscript>

Nun eine Überschrift und die beide Formulare umfassende Tabelle:

<h2>Kalender</h2>

<table cellspacing="0" cellpadding="10">
  ...Zeile mit control-Formular...
  ...Zeile mit eigentlichem Kalender...
</table>

Zeile mit control-Formular

Das control-Formular können wir noch gut in reinem HTML ausdrücken:

<tr><td align="center">
<form name="control">
<input type="button" value=" &lt;&lt;- " onclick="prevYear();" style="width:50px;">
<input type="button" value=" &lt;-- " onclick="prevMonth();" style="width:50px;">
<input type="button" name="t" value="XXXXXXXXXXX" onclick="info();" style="width:150px;">
<input type="button" value=" --&gt; " onclick="nextMonth();" style="width:50px;">
<input type="button" value=" -&gt;&gt; " onclick="nextYear();" style="width:50px;">
</form>

Wir geben den Button mit einem einfachen CSS-Style eine gewisse Breite. Die X diesen dazu, dem mittleren Button auch dann ein Breite zu geben, wenn CSS nicht verfügbar ist.

Über onclick benennen wir die auszuführenden und noch zu implementierenden Operationen.

Wir lagern diese in separate Funktionen aus.

Der mittlere Button hat als einziger einen Namen ist, weil wir seinen Wert anpassen und ihn unabhängig von seiner (relativen) Position machen wollen. Wir können ihn also immer mit document.control.t ansprechen, egal wo das Formular und wo der Button im Formular steht.

Zeile mit eigentlichem Kalender

Nun zum Kalender selbst: Dieser wird - wie schon erwähbt - als zweite Zeile der Tabelle gesetzt. Der Zelleninhalt ist ein Formular "cal", welches selbst eine Tabelle enthät.

Diese Tabelle besteht aus einer Zeile mit Überschriften (Kurzformen für Tagesbezeichnung) und sechs Zeilen mit je sieben Buttons. Die Implementierung erfolgt naheliegend mit zwei geschachtelten for-Schleifen:

<script type="text/javascript"><!--

// Kopfzeile

document.write('<tr><td align="center">');
document.write('<form name="cal"><table>');
document.write('<tr><th>Mon</th><th>Die</th>',
              '<th>Mit</th><th>Don</th>',
              '<th>Fre</th><th>Sam</th>',
              '<th><font color="#cc3333">',
              'Son</font></th></tr>');

// Matrix

  for (var y=1; y <= 6; y++) {
    document.write('<tr>');
    for (var x=1; x <= 7; x++) {
      document.write('<td>');
      document.write('<input type=button value="XXX" name="z', z, '" style="width:50px;">>');
      document.write('</td>');
    }
    document.write('</tr>');
  }

  document.write('</table></form>');
  document.write('</td></tr>');
// -->
</script>

Den schwersten Teil hätten wir damit schon abgehandelt. Die X dienen wieder dazu, eine gewisse Breite zu erzeugenm sofern der CSS-Style nicht ausgewertet wird.

Implementierung der Funktionalität

Wir werden in globalen Variablen month und year den jeweils gerade angezeigten Kalender halten. Um den aktuellen Tag besonders hervorzuheben, halten wir in globalen Variablen nday, nmonth und nyear das jeweils aktuelle Datum.

Diese machen wir dem System erstmal mit irgendwelche Werten initialisiert bekannt:

var nday = 10;
var nmonth = 4;
var nyear = 1999;
var month = 4;
var year  = 1999;

Zur Initialisierung, d.h. zum erstmaligen Ausfüllen des Kalenders, stellen wir das aktuelle Datum fest, setzen die Werte entsprechend und zeichnen den Kalender:

function init() {
  var act = new Date();

  month = act.getMonth()+1;
  year = act.getFullYear();

  nmonth = month;
  nyear = year;
  nday = act.getDate();

  update();
}

Diese Funktion lassen wir durch den onload-Handler von body automatisch ausführen, wenn die Seite geladen ist. - nichts Neues:

<body onload="init();">

Die Implementierung der Steuerelemente ist naheliegend. Je nachdem was angeklickt wurde, werden die Werte month und year angepasst und dann der Kalender mit update() neu gezeichnet:

function prevMonth() {
  if (--month == 0) {
    month = 12;
    year--;
  }
  update();
}

function nextMonth() {
  if (++month == 13) {
    month = 1;
    year++;
  }
  update();
}

function prevYear() {
  year--;
  update();
}

function nextYear() {
  year++;
  update();
}

In dem mittleren Feld t der Steuerung wollen wir eine natürlichsprachliche Darstellung von Monat und Jahr sehen.

Darüber hinaus haben wir diesen Button mit der Funktion info() belegt, die lediglich ein Meldung ausgeben soll.

Wir brauchen also die Monatsnamen, die wir schon kennengelernt hatten und die Funktion info():

var monNames = new Array(
  'Januar', 'Februar', 'M&auml;rz', 'April',
  'Mai', 'Juni', 'Juli', 'August',
  'September', 'Oktober', 'November', 'Dezember'
);

function info() {
  alert('\nKalender v1.02\n\nin JavaScript\n\n',
        '(c) 1999, Thomas Salvador, Freeware.\n',
        'https://brauchbar.de\n\n',
        'Sie koennen das unveraenderte Script',
        'nach Belieben verwenden.');
}

Tatsächlich fehlt jetzt nur noch die Funktion update(), die den Kalender in die Buttons zaubert. Diese stützt sich auf das Julianische Datum ab. So sind wir nicht auf den in JavaScript gegebenen Datumsbereich beschränkt und können (trotzdem) leicht mit Daten rechnen.

Wir hatten den Buttons keine Namen gegeben, da wir sie in Ihrer Reihenfolge ansprechen: Mit document.cal.elements[i] können wir auf das i-te Element (hier den i-ten Button) zugreifen. Auch dieses Feld ist zero-based. Fangen wir an: Wir machen verwendete Variablen bekannt:

function update() {
  var x = 0;
  var y = 0;
  var l = 0;
  var i = 0;

Nun melden wir im t-Feld, dass etwas passiert und löschen der Einfachheit halber alle Buttons des aktuellen Kalenders:

document.control.t.value = 'Einen Moment bitte...';

for (x = 0; x < 42; x++)
  document.cal['z'+x].value=' ';

Wir müssen wissen, wieviele Tage der darzustellende Monat hat und auf welchen Wochentag der 1. dieses Monats fällt. Beides ist mit dem Julianischen Datum trivial machbar.

x = ymd2julian(year, month, 1);
l = ymd2julian(year, month+1, 1)-x;

x = (x % 7);

Zunächst hat x das julianische Datum des 1. Tag des dargestellten Monats.

In einem zweiten Schritt wird l die Differenz von Julianischen Datum des 1. des Folgemonats und x zugewiesen.

Aufgrund der Linearität des Julianischen Datums – haben wir heute das Julianische Datum a, so haben wir mogen a+1, übermorgen a+2, usw. – trägt l damit die Anzahl der Tage des dargestellten Monats.

In einem finalen Schritt wird x der Wert x modulo 7 zugewiesen, wodurch wir den Wochentag ermitteln. Manche Leser werden hier einen Unterschied in der Berechnung zur Tag der Woche-Funktion bemerken.

Dieser ist dadurch begründet, dass wir in dem genannten Artikel allgemein verwendbare Funktion kreieren wollten, die möglichst einfach verwendet werden kann.

Der Unterschied bewirkt lediglich eine Änderung Bedeutung der gelieferten Werte von 0 bis 6.

Hier wurde diese Version verwendet, da es nur eine interne, nicht zur Wiederverwendung gedachte Funktion ist.

Jetzt füllen wir den Kalender in einer einfachen for-Schleife über die Anzahl der Tage l:

for (i = 1; i <= l; i++) {
  document.cal['z'+(x+i-1)].value=' '+i;
}

Die folgende if-then-Unterscheidung hebt den aktuellen Tag hervor, wenn er im jeweils angezeigten Monatsblatt dargestellt ist:

if ((year == nyear) && (month == nmonth)) {
  document.cal.elements[x+nday-1].value = '{'+nday+'}';
}

Nun tragen wir noch die natürlichsprachliche Bezeichnung des Kalenderblattes ein:

document.control.t.value = monNames[month-1]+' '+year;

Fertig!

Kalender

Viel Spaß.