Javascript

Blog-Kalender Marke 'Eigenbau' via AJAX

Mit Javascript und XML dynamischen Kalender erstellen

Viele Blogs haben einen Kalender am linken oder rechten Rand der Seite, der aufzeigt, wann der Autor des Blogs Beiträge geschrieben hat. Mit einem Klick auf einen Tag gelangt man zu den an diesem Tag eingestellten Artikeln. Solche Kalender werden von der jeweiligen Blog-Software (z.B. WordPress) automatisch erzeugt.

Webmaster, die nicht über eine solche Software zum Einstellen Ihrer Beiträge verfügen, bzw. ihr Web auf einem ganz normalen Web-Server ohne Zusatz-Features hosten, müssen sich einen solchen Kalender selbst schreiben. So auch ich. Der erste Ansatz war natürlich, das Ganze, wie der Rest von zerbit.de auch, in ASP zu entwickeln, aber das hat, wie bei den meisten Blogs, den Nachteil, dass der Sprung zu einem anderen Monat über einen entsprechenden Monatsselektor die Seite immer neu geladen werden muss.

Dieses Problem läßt sich eigentlich nur mit Javascript lösen, das nicht auf dem Server, sondern auf dem Client ausgeführt wird. Einen dynamischen Kalender mit Javascript zu erstellen ist ja nicht allzu schwer, aber wie bekommt man es hin, die Tage, an denen Beiträge eingestellt wurden, im Kalender zu verlinken? Dazu braucht man auswertbare Daten vom Datenbank-Server, was wiederum für eine Server-Sprache wie ASP oder PHP spricht.

Des Rätsels Lösung geistert seit einigen Monaten durch die einschlägigen Medien: AJAX! Dieser Begriff steht für "Asynchrones Javascript und XML" und bezeichnet eine Technik Daten dynamisch auf eine Web-Seite per Javascript nachzuladen. Das Ganze ist beileibe nicht neu, denn die zugrunde liegende Technologie steht seit Jahren zur Verfügung, aber das Ganze hat nun einen griffigen Namen und damit steht dem Hype nichts mehr im Wege.

In Kurzform kann man AJAX so umschreiben: eine Seite wird komplett geladen. Der Benutzer klickt auf einen Link oder eine Schaltfläche, wobei eine Javascript-Funktion aufgerufen wird, die mittels des XMLHTTP-Objektes vom Server eine XML-Datei abruft und verarbeitet. Diese XML-Datei liegt jedoch nicht starr auf irgendeiner Festplatte, sondern wird dynamisch mittels ASP, PHP oder einer anderen Server-Sprache erzeugt.

Für unseren Fall ist das genau das Richtige. Wir brauchen also eine Javascript-Funktion, die beim Seitenaufbau eine tragende Tabelle erzeugt und eine weitere, die dynamisch die Daten eines gewählten Monats in diese Tabelle schreibt, wobei die Daten per XML vom Server abgeholt werden. Ein Beispiel für eine Implementierung sehen Sie am linken Rand dieser Web-Seite (Kalender).

Die Tabelle

Folgende kleine Javascript-Funktion erzeugt eine Tabelle mit insgesamt 7 Zeilen und 7 Spalten, wobei die erste Zeile für den Kalenderkopf und der Rest für die einzelnen Tage verwendet wird.

function createCalendar()
{
   var sHTML;
   var i;

   // Tabellen-Code zusammenstellen
   sHTML = '<table class="cal">';
   sHTML += '<tr><td id="calHead1">'
   sHTML += '<a href="">&lt;</a></td>';
   sHTML += '<td id="calHead2" colspan="5"></td>';
   sHTML += '<td id="calHead3">'
   sHTML += '<a href="">&gt;</a></td></tr>';
   sHTML += '<tr>';

   // Tabelle mit 6 Zeilen und 7 Spalten erstellen
   for(i = 1; i <= 42; i++) {

      sHTML += '<td id="calCell' + i + '">&nbsp;</td>';

      // Umbruch nach jeder 7. Zelle
      if(i==7 || i==14 || i==21 || i==28 || i==35) {
         sHTML += '</tr><tr>'; }
      }

      sHTML += '</tr></table>';

   // Kalender ausgeben
   document.write(sHTML);
}

Wir müssen darauf achten jeder Zelle eine eindeutige ID mitzugeben, denn später muss auf jede einzelne Zelle per getElementById-Methode zugegriffen werden, um die entsprechenden Daten unterzubringen. Die ID's des Kaelnderkopfes heißen in unserem Fall calHead1, calHead2 und calHead3. Die ID's der einzelnen Tageszellen heißen fortlaufend calCell1, calCell2, calCell3, et cetera.

Mit der letzten Anweisung (document.write(sHTML);) wird der zusammengestellte Tabellen-Code an der aktuellen Stelle in der HTML-Seite ausgegeben. Hierzu wird folgender HTML-Code verwendet:

<script type="text/javascript">createCalendar();</script>

Die XML-Datei

Als nächstes brauchen wir die Daten der Beiträge im XML-Format. Da wir lediglich Links im Kalender erzeugen wollen, mit denen der Benutzer zu einer speziell angefertigten ASP- oder PHP-Seite mit den Beiträgen eines Monats surfen kann, brauchen wir einzig und allein die Anzahl der Beiträge für jeden Tag eines bestimmten Monats. Die Struktur einer solchen "XML-Datei" ist relativ simpel:

<content>
   <day id="1">0</day>
   <day id="2">3</day>
   <day id="2">1</day>
   ...
   <day id="30">1</day>
   <day id="31">0</day>
</content>

Jeder Tag eines Monats besitzt ein DAY-Tag, daß die Anzahl der Beiträge einschließt. Wie man XML-Dateien z.B. mit ASP direkt auf dem Server erzeugt, kann im zerbit.de-Artikel RSS-Feed direkt mit ASP erzeugen nachgelesen werden.

In unserem Fall existiert eine ASP-Seite mit dem dem Namen contentcount.asp, die zwei Parameter auswerten kann: m für den Monat und y für das Jahr. Der Aufruf für die oben abgebildete XML-Ausgabe für den September 2005 sieht dann so aus:

contentcount.asp?m=9&y=2005

Füllen der Tabelle mit Daten

Direkt unter den Aufruf der Funktion createCalendar auf der HTML-Seite, legen wir den Aufruf der Daten-Hauptfunktion getCalendar, die die Befüllung der Tabelle mit den einzelnen Tagen inkl. der Links erledigt:

<script type="text/javascript">getCalendar();</script>

Diese Funktion ist eine Hüllenfunktion, die eine weitere Funktion (fillCalendar) aufruft, sobald die XML-Daten vom Server empfangen wurden. Dieser Umweg ist notwendig, da wir zum Laden der Daten das XMLHTTP-Objekt verwenden und es eine gewisse Zeit braucht, bis die Daten an den Client übertragen wurden. Die Funktion im einzelnen:

Wir benötigen zunächst zwei globale Variablen, die außerhalb der Funktion deklariert werden:

var xmlHttp = false;
var sDate;

Die ersten Zeilen im Code der Funktion stellen sicher, daß die Funktion auch läuft, wenn keine Parameter übergeben wurden. In diesem Fall wird der aktuelle Monat berechnet.

Wichtig: In Javascript beginnt die Monatszählung bei 0, d.h. die Zahl 0 repräsentiert den Januar, 1 den Februar, et cetera. Dies muss bei der Übergabe des Parameters iMonth und im folgenden Code beachtet werden.

function getCalendar(iMonth, iYear)
{
   // aktuelles Datum in Variable speichern
   sDate = new Date();

   // wenn Parameter leer, dann aktuellen Monat verwenden
   if (iMonth == null) {
   iMonth = sDate.getMonth();
   iYear = sDate.getFullYear(); }
...

Weiter geht es mit der Initialisierung des XMLHTTP-Objekts. Hier müssen wir, aufgrund der unterschiedlichen Umsetzungen der einzelnen Browser, eine Weiche einbauen, um das Objekt auch sicher zu initialisieren:

...
   // Mozilla und Co.
   if (window.XMLHttpRequest) {
      xmlHttp = new XMLHttpRequest(); }
   // IE
   else if (window.ActiveXObject) {
      xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); }
   else {
      // Falls nicht unterstützt
     
xmlHttp = false; }
...

Nun stellen wir in einer Variablen die URL wie oben zusammen mit der XML-Daten abgeholt werden. Dabei ist darauf zu achten, daß die Variable iMonth um 1 erhöht wird, um den richtigen Monat abzurufen. Anschließend wird die Methode open des XMLHTTP-Objekts ausgeführt, d.h. der Datentransport wird gestartet. Wichtig hierbei ist der letzte Parameter, der angibt, ob die Daten asynchron oder nicht geladen werden sollen.

...
   // URL zusammenstellen und Inhalt über GET asynchron holen
  
var sXMLUrl = 'http://meinserver/contentcount.asp?m=' + (iMonth + 1) + '&y=' + iYear;
   xmlHttp.open("GET", sXMLUrl, true);
...

Was nun folgt ist die Zuweisung einer Inline-Funktion zur Eigenschaft onreadystatechange. Damit wird erreicht, daß die Funktion fillCalendar ausgeführt wird, sobald das Objekt den Ladestatus 4 ("loaded") und den Dokumentenstatus 200 ("OK") meldet. In der letzten Zeile wird der so aufgebaute Request dann an den Web-Server gesendet:

...
   xmlHttp.onreadystatechange = function() {

      // Objekt meldet "loaded"
      if (xmlHttp.readyState == 4) {
         // Objekt meldet "OK"
         if (xmlHttp.status == 200) {
            // Funktion zum Füllen der Tabelle ausführen
            fillCalendar(iMonth, iYear); }
      }
   }
   xmlHttp.send(null);
}

Nun zur Funktion fillCalendar, die eigentliche Arbeit erledigt. Die ersten Zeilen beschäftigen sich zunächst mit der Initialisierung eines Monats-Arrays und einigen benötigten Datumsberechnungen:

function fillCalendar(iMonth, iYear)
{
   // Monats-Array bilden
   var aMonths = new Array(
      'Jan.', 'Febr.', 'Mär.', 'Apr.',
      'Mai', 'Jun.', 'Jul.', 'Aug.',
      'Sep.', 'Okt.', 'Nov.', 'Dez.');

   // Monate ermitteln
   var iThisMonth = new Date(iYear, iMonth, 1);
   var iPrevMonth = new Date(iYear, iMonth - 1, 1);
   var iNextMonth = new Date(iYear, iMonth + 1, 1);

   // Erster Wochentag und Anzahl Tage/Monat ermitteln
   var iFirstWeekday = iThisMonth.getDay();
   if (iFirstWeekday == 0) iFirstWeekday = 7;
   var iDaysInMonth = Math.floor((iNextMonth.getTime()
     - iThisMonth.getTime()) / (1000 * 60 * 60 * 24));
...

Als nächstes wird der Tabellenkopf anhand der in der HTML-Tabelle definierten ID's befüllt. Zu beachten ist, daß die beiden Monats-Links zum vorherigen bzw. nächsten Monat wiederum die oben dargestellte Funktion getCalendar aufrufen, um die Daten eines anderen Monats in die Tabelle einzutragen:

...
   // Link zu vorherigem Monat
   var sPrev = '<a href="javascript: getCalendar('
      + iPrevMonth.getMonth() + ','
      + iPrevMonth.getFullYear() + ')">&lt;</a>';
   hItem = document.getElementById("calHead1")
   hItem.innerHTML = sPrev;

   // Überschrift aus Monats-Array
   hItem = document.getElementById("calHead2")
   hItem.innerHTML = aMonths[iMonth] + ' ' + iYear;

   // Link zu nächstem Monat
   var sNext = '<a href="javascript: getCalendar('
      + iNextMonth.getMonth() + ','
      + iNextMonth.getFullYear() + ')">&gt;</a>';
   hItem = document.getElementById("calHead3")
   hItem.innerHTML = sNext;
...

Da wir einen Monatskalender darstellen wollen, müssen wir in der Tabelle zunächst alle Zellen der ersten Zeile mit Blanks füllen, deren Tage im letzten Monat liegen:

...
   // Leere Tage am Anfang auffüllen
   for(iCellId=1; iCellId < iFirstWeekday; iCellId++) {
      hItem = document.getElementById("calCell" + iCellId);
      hItem.innerHTML = '&nbsp;'; }
...

Nun kommen wir zu den Tages des darzustellenden Monats. Hier werden zunächst zwei Variablen initialisiert, wobei die erste das XML-Dokument darstellt, dass wir über die Eigenschaft responseXML des XMLHTTP-Objekts erhalten. Es beinhaltet den kompletten Code des XML-Dokuments.

...
   // XML-Objekt initialisieren
   var xmlDok = xmlHttp.responseXML;

   // Variable initialieren
   var iCellDay=1;
...

Die einzelnen Tage werden über eine Schleife generiert, die alle Tage des Monats durchläuft:

...
  // Schleife über alle Tage des Monats
  for(iCellId = iFirstWeekday; iCellDay <= iDaysInMonth; iCellId++) {
...

Die erste Aktion innerhalb der Schleife ist die Anzahl der Beiträge für den aktuell zu verarbeitenden Tag aus den XML-Daten zu bestimmen. Hierzu verwenden wir die DOM-Funktion getElementsByTagName und sehen uns den Index des benötigen Tags an. Ist dieser 0, so wird als Ausgabe-String lediglich die Zahl des Tages verwendet. Bei einem Wert größer Null, enthält der Ausgabe-String einen Link zu einer ASP-Seite, die die einzelnen Beiträge eines Tages ausgibt.

...
      // Anzahl Beiträge aus XML ermitteln
      iItemCount = xmlDok.getElementsByTagName("day")
         [iCellDay - 1].firstChild.nodeValue;

      // Zellinhalt bestimmen (Link auf Beiträge oder nicht)
      if (iItemCount == 0) {
         sDayHTML = iCellDay; }
      else {
         var sDayString = iCellDay + "." + (iMonth + 1) + "." + iYear;
         sDayHTML = '<a href="/showdatum.asp?day='
            + sDayString + '">' + iCellDay + '</a>';
      }

      // Zellinhalt zuweisen
      hItem = document.getElementById("calCell" + iCellId)
      hItem.innerHTML = sDayHTML;

      iCellDay++;
   }
...

Damit wäre die Schleife über alle Monatstage erledigt. Zum Abschluss der Funktion brauchen wir der Vollständigkeit halber noch etwas Code zum Auffüllen der restlichen Zellen mit Blanks für die Tage der Woche die bereits im neuen Monat liegen.

...
   // Leere Tage am Ende auffüllen
   for(iCellId; iCellId <= 42; iCellId++) {
   hItem = document.getElementById("calCell" + iCellId)
   hItem.innerHTML = '&nbsp;'; }
}

Die Elemente der HTML-Tabelle können nun noch entweder direkt über Funktion createCalendar oder während dem Befüllen mit Daten mit CSS-Klassen versehen werden, um das Ganze etwas aufzuhübschen.

Downloads

ajax_calendar.js
kick it on dotnet-kicks.de AddThis Trackback-Url...

5 Kommentare bislang...

  • Ein wirklich brauchbarer Kalender, thx.
    5
    motorsport : Dienstag, 25. Mai 2010 20:41
  • Netter Kalender - vielleicht kann ich sowas ähnlich auf meiner Homepage versuchen - gute Idee
    4
    Christian : Montag, 3. Mai 2010 08:17
  • Hey, sieht super aus, danke dafür
    3
    itema : Montag, 2. November 2009 15:05
  • Hey, danke für diese Erstklassige Beschreibung!!!
    2
    MIra Esslingen : Montag, 6. Juli 2009 13:48
  • Vielen Dank für die ausführliche Hilfestellung zum Einrichten meines Kalenders! Ich bin begeistert!
    1
    Warhol : Montag, 22. September 2008 19:38

Dein Kommentar hierzu...


Kommentar-Feed für diesen Beitrag
Gravatare werden unterstützt .:. eMail-Adressen werden nicht veröffentlicht
 

RSS-Feed

Die URL des Standard-Newsfeed von zerbit.de lautet:

http://www.zerbit.de/rssfeed.aspx

Login


 

 

Statistik



kürzlich kommentiert

Artikel 50

  • Datum: 21.11.2005
    Kategorie: Javascript
    Zugriffe: 6.094
    Kommentare: 5
    Trackbacks: 0

Letzte Beiträge

Kategorien

Buttons & More

Blog-Roll

Banner Piraten-Partei