Pimp My RapidWeaver: Lightbox JS

Verwenden von Lightbox JS mit dem RapidWeaver Fotoalbum

Ausgangssituation

Im Netz existieren einige Tutorials und Anleitungen darüber, wie man das Lightbox JavaScript in RapidWeaver Seiten verwendet. Doch diese Anleitungen beziehen sich dann meist auf selbst zusammengestellte Bilderseiten. Grundsätzlich gefiel mir aber die Funktionalität der "Fotoalbum" Seite, die mit RapidWeaver geliefert wird. Nur hätte ich dort halt gerne diesen sagenhaften Effekt genutzt.
Mein erster Ansatz war natürlich selbst ein RapidWeaver Plugin zu entwickeln. Diese Idee habe ich dann aber erst einmal zurück gestellt. Mangelnde Zeit (die ich hoffentlich irgendwann haben werde) für die Einarbeitung in die Mac Entwicklung allgemein, und die RapidWeaver Programmierung im speziellen, haben mich zu einer anderen Lösung gebracht.

Ziel

Seiten, die mit dem RapidWeaver "Fotoalbum" angelegt wurden, sollen mit möglichst geringem Aufwand (von dem einmaligen Aufwand der Lösungserstellung abgesehen) den Lightbox Effekt nutzen können.

Lösung

Ein Theme mit Lightbox Unterstützung

Die Lösung wird in ein Theme eingebettet. D.h. bei Verwendung des Themes kann das Fotoalbum, wenn gewünscht mit Hilfe der Lightbox angezeigt werden. Als Grundlage hierfür packen wir also zunächst die Lightbox Dateien in das Theme-Verzeichnis und sorgen dafür, dass die Dateien kopiert und eingebunden werden. Die Dateien werden kopiert, wenn sie bzw. das Verzeichnis in dem sie enthalten sind, in der Theme.plist Datei im Abschnitt "RWCopyFiles" aufgeführt werden. Ich habe das komplette Lighbox-Verzeichnis in ein "js"-Verzeichnis im Theme kopiert und es im Abschnitt "RWCopyFiles" angegeben. Um die Dateien dann auch zu verwenden, müssen sie in der "index.html" des Themes eingebunden werden. Benötigt werden die JavaScript-Dateien "prototype.js", "scriptaculous.js" und "lightbox.js", sowie die "lightbox.css" Datei.
Bei Prototype und Scriptaculous habe ich jeweils die aktuellste stable Version (Prototype 1.5, Scriptaculous 1.7) direkt von den entsprechenden Webseiten geladen und zusätzlich im "js"-Verzeichnis abgelegt. Gerade die aktuelle Prototype Version bringt einige recht nütliche Erweiterungen mit sich, die beim nachfolgenden Script rege gebraucht werden.

<html xmlns="http://www.w3.org/1999/xhtml";>
<head>
  %header%
  <title>%title%</title>
  <link rel="stylesheet" type="text/css" media="screen" href="%pathto(styles.css)%"  />
  <link rel="stylesheet" type="text/css" medie="screen" href="%pathto(js/lightbox2/css/lightbox.css)%"  />
  <link rel="stylesheet" type="text/css" media="print" href="%pathto(print.css)%"  />
  <link rel="stylesheet" type="text/css" media="handheld" href="%pathto(handheld.css)%"  />
  %style_variations%
  %user_styles%
  <script type="text/javascript" src="%pathto(js/javascript.js)%";></script>
  <script type="text/javascript" src="%pathto(js/prototype.js)%"></script>
  <script type="text/javascript" src="%pathto(js/scriptaculous-js-1.7.0/scriptaculous.js)%"></script>
  <script type="text/javascript" src="%pathto(js/lightbox2/js/lightbox.js)%"></script>
  %user_javascript%
</head>
...

Modifizieren der Fotoalbum Seiten

Damit die Lightbox verwendet wird, muss eine Seite Links auf Bilder enthalten. Diese Links müssen außerdem mit einem zusätzlichen "rel" Tag versehen sein, welches den Wert "lightbox[...]" enthält. Die genau Funktionsweise von Lightbox setze ich als bekannt voraus bzw. kann hier nachgelesen werden. Nun ist es aber so, dass RapidWeaver beim Fotoalbum Links auf Seiten liefert, die dann erst die Bilder enthalten. Auf die Funktionsweise bzw. die Ausgabe des Plugins haben wir keinen Einfluss, also versuchen wir einfach die Ausgegebene Seite nachträglich mittels JavaScript zu modifizieren.
Eine Analyse des Quelltextes ergibt, dass das Fotoalbum für jedes Bild einen DIV mit der Klasse "thumbnail-frame" erzeugt. In diesem DIV ist der Link auf die Fotoseite enthalten. Optional kann noch ein Paragraph "p" enthalten sein, der den Tietel des Bildes enthält. Wir werden also mittels JavaScript den Link abändern und die Attribute "rel" und "title" ergänzen. Für uns arbeitet die Tatsache, dass die Fotoseite den gleichen Namen trägt, wie das auf ihr plazierte Bild. D.h. bei dem vorhandenen Link müssen wir nur die Dateiendung von ".html" auf ".jpg" ändern. Durch das Setzen des "title" Attributes wird der Titel des Bildes auch in der Lightbox angezeigt!
Und so sieht der Quellcode dafür aus:

function lightboxImages() {
  // Thumbnails aus dem Inhalt der Seite heraussuchen.
  var content = $('content');
  var thumbnails = $$('.thumbnail-frame');
  for (i = 0; i < thumbnails.length; i++) {
    // Link im Thumbnailframe suchen.
    var link = thumbnails[$i].getElementsByTagName('a')[0];
    // Auslesen der URL aus dem Link, Dateiendung ersetzen und neu URL eintragen.
    var newHref = link.getAttribute("href").replace(/\.html/, ".jpg");
    link.setAttribute("href", newHref);
    // Hinzufuegen des rel Attributes
    link.setAttribute("rel", "lightbox[gallery]");
    // Wenn eine Caption angegeben ist, soll diese als Titel des Links gesetzt werden.
    var caption = thumbnails[i].getElementsByTagName('p')[0];
    if (caption && caption.firstChild) {
      link.setAttribute("title", caption.firstChild.data);
    };
  };
} 

Die Funktion habe ich in der Datei javascript.js verstaut, die ich von einem vorhandenen RapidWeaver Theme übernommen habe. Für das Kopieren und Einbinden der Datei haben wir bereits gesorgt. Jetzt muss nur noch der Aufruf der Funktion ausgeführt werden. Der Aufruf der Funktion darf natürlich erst erfolgen, wenn das Dokument vollständig geladen ist. Es bietet sich also an, entwede die "onLoad" Funktion vom "body"-Tag oder von "window"-JavaScript Objekt zu verwenden. Da ich die Funktion nicht einfach auf jeder Seite ausführen lassen will, sondern nur auf den Seiten, die ein Fotoalbum enthalten, fällt das feste Einbinden in "body"-Tag des Templates weg. Beim Verwendung von "window.onload" besteht das Problem, das nur eine Funktion angegeben werden kann, aber eventuell mehrere benötigt werden. Z.B. enthält die "javascript.js" Datei bereits eine Funktion "externalLinks", die automatisch aufgerufen werden soll. Zur elleganten Lösung dieses Problems, habe ich mir einen netten Mechanismus bei Rico abgekuckt. Alle Funktionen, die nach dem Laden des Dokuments aufgerufen werden sollen, werden in einem Array gespeichert. Ein Funktion, die alle im Array gepseicherten Funktionen aufruft, wird über "body"/"onLoad" im Template gestartet. Das ganze habe ich wiederum in der "javascript.js" verstaut.

var onloads = new Array();
function bodyOnLoad() {
  for ( var i = 0 ; i < onloads.length ; i++ ) {
    onloads[i]();
  };
}

Durch diesen Mechanismus kann mann einfach Funktionen hinzufügen, die nach dem Laden des Dokuments aufgerufen werden sollen. Dies kann entweder in den ".js" Dateien erfolgen, oder geziehlt im Page-Inspector unter "Seiten-Informationen / Code / Eigenes JavaScript" für jede Seite eingefügt werden. Für die "lighboxImages"-Funktion muß z.B. folgende Codezeile im Pageinspector eingefügt werden:

onloads.push(lightboxImages);

Die "externalLinks" Funktion wird natürlich auf diesen Mechanismus umgestellt.
Jetzt kann das erste mal getestet werden und normalerweise sollte das ganze funktionieren. Ein kleines Problem tauch jedoch noch auf. Die Bilder der Schließen-Schaltflächen und des Ladevorganges werden nicht angezeigt.

Pfade für die Bilder anpassen

Jeder der Lightbox JS schon einmal verwendet hat weiß natürlich, dass der Pfad der beiden Bilder einfach in der Datei ligthbox.js angepasst werden muss. Ganz so einfach ist es in diesem Fall jedoch nicht. Zumindest dann nicht, wenn die Option "Zusammengehörige Dateien verbinden" in RapidWeaver aktiviert ist, wovon ich jedoch ausgehe. Diese Option sorgt dafür, dass alle Theme-Dateien nur einmal für die Seite abgelegt werden, und zwar unterhalb des rw-common Verzeichnis. Das Problem ist nun, dass wir den relativen Pfad zu den Bilder nicht kennen, und die Funktion "path-to", die wir in der "index.html" Datei des Themes verwenden, in der JavaScript Datei natürlich nicht verwendet werden kann. Und da wir es auch vermeiden wollen absolute Pfade zu verwenden, müssen wir noch einmal in die JavaScript Trickkiste greifen.
Wir holen uns einfach das erstbeste "link" Tag aus der aktuellen Seiten, das keinen absoluten Pfad enthält und extrahieren aus dessen "href" Attribut den Pfad der von der aktuellen Seite zum Wurzelverzeichnis führt. Das ganze geht so:

var rw_docroot = "";
var currPath = "";
var tagNo = 0;
do {
  currPath = document.getElementsByTagName("link")[tagNo].getAttribute("href");
  tagNo++;
} while (currPath.substr(0, 4) == "http");
var rwCommonPos = currPath.indexOf("rw_common");
rw_docroot = currPath.substring(0, rwCommonPos);

Diese Zeilen werden in der Datei "lightbox.js" vor den Pfadangaben eingefügt. Anschließend können wir die Pfade wie folgt setzen:

var fileLoadingImage = rw_docroot + "rw_common/themes/THEMENAME/js/lightbox2/images/loading.gif";
var fileBottomNavCloseImage = rw_docroot + "rw_common/themes/THEMENAME/js/lightbox2/images/closelabel.gif";

Nach dieser ergänzung sollten die Bilder nun angezeigt werden, egal an welche Position im Seitenbaum sich die Fotoalbum-Seite befindet.

Erfahrungen

Wärend der Entwicklung der Lösung habe ich festgestellt, dass die Reihenfolge, in der die JavaScript-Datien und CSS-Dateien geladen werden, nich ganz unrelevant sind. Es ist mir beispielwiese ab und an passiert, das mein Script zwar korrekt abgelaufen und alle benötigten Dateien eingebunden waren, der Lightbox Effekt aber trotzdem nich funktioniert hat. Zum teil auch nur in bestimmten Browsern. Den genauen Grund konnte ich mangels Fehlermeldungen oder anderer Hiweise nicht herausfinden. Die oben genannte Reihenfolge funktioniert bei mir jetzt jedoch in allen Browsern. Und wenn auch die Reihenfolge nicht den erwünschten Effekt erziehlt, kann mann als letzte Rettung die Initialisierung des Scripts noch einmal explizit vornehmen. Konkret würde das im hier gezeigten Beispiel bedeuten, dass im "onloads" Array noch ein Aufruf der Funktion "initLightbox" hinzugefügt wird.

Fazit

Nach dem ich das Script im Laufe der Zeit einige male überarbeitet habe, bin ich jetzt schon ganz zufrieden damit. Angenehmer Nebeneffekt dieser Lösung ist, dass immer noch die normalen HTML Seiten mit der Großen Bildansicht und der Möglichkeit "manuell" zu Blättern erzeugt werden. Somit bekommen auch Benutzer mit deaktiviertem JavaScript oder Suchmaschinen ein vernünftiges Ergebnis.
Ich hoffe dieses Tutorial trifft den geschmack einiger RapidWeaver Benutzer und würde mich über Resonanz im zugehörigen Blog-Eintrag oder über das Kontaktformular freuen.

Werbung