Im folgenden Tutorial stelle ich den Aufbau und die Struktur eines kleinen Online-Portfolios vor. Erläutert werden sämtliche Codeabschnitte und der Zusammenhang verschiedener Scriptsprachen. Die Portfolio-Webseite arbeitet mit der Metapher eines unsortierten Fototisches. Per Zufall werden verschiedenste Dateien aus einem Ordner auf dem Webserver ausgelesen und willkürlich auf der Arbeistfläche verteilt. Fotos werden als Miniaturen abgebildet und beim „Drüberfahren“ mit der Maus werden diese vergrößert. Das Miniportfolio dient mehr dazu, einen kleinen Einblick einer Auswahl an Arbeiten zu verschaffen, als eine strukturierte Präsentation sämtlicher Projekte zu bieten.
Das Miniportfolio arbeitet grundsätzlich mit drei bekannten Script- und Programmiersprachen. HTML(5) und CSS, PHP, Javascript.
Der Schwerpunkt der Programmierarbeiten liegt in diesem Fall sicherlich im Bereich PHP. PHP ist eine serverseitige Scriptsprache, d.h. sie kann nur am Server ausgeführt werden. Siehe http://php.net/manual
Voraussetzungen:
Da ein Großteil der Programmierarbeiten mit PHP realisiert werden muss, wird dazu geraten sich eine lokale Testumgebung einzurichten. Anleitungen und Tutorials im Einsatz rund um MAMP (Mac) und XAMPP (Windows) finden Sie hier:
http://www.mamp.info
http://www.apachefriends.org
Weiters wird ein grundlegendes Wissen diverser HTML Entities und CSS Selektoren vorausgesetzt.
http://www.w3schools.com/css
http://www.w3schools.com/html
Ein Beispiel des Miniportfolios findet man auf meiner persönlichen Webseite.
Das gesamte Projekt kann als .zip-Datei hier heruntergeladen werden.
Wie jedes HTML Dokument beginnt auch dieses mit der Deklaration eines Doctypes.
Der Doctype gibt wie das Wort schon sagt den Typ des Dokuments an. In unserem Fall handelt es sich um ein HTML5 Dokument und somit wird am Beginn unseres index.php ein gesetzt.
Obwohl unser Dokument als index.php definiert ist, handelt es sich im Inhalt des Dokuments um HTML. Da wir in unserem index Dokument jedoch auch PHP verwenden, muss das Format des Dokuments auch dementsprechend als .php definiert werden.
Der restliche Aufbau des Webdokuments funktioniert in HTML5 gleich wie immer. Im <head> Bereich werden die nötigen Meta-Angaben definiert, Stylesheets (CSS) eingebunden und auf die benötigten Javascript Dateien verwiesen.
Zu beachten ist hier, dass Frameworks und Libraries wie jQuery vor anderen Script-Dateien geladen werden müssen, damit diese bereits für die später geladenen JS-Files zur Verfügung stehen.
Nach dem <head> folgt der <body> des Dokuments der unseren sämtlichen PHP-Code des Front-end trägt.
Als Front-end wird der Bereich der Webseite bezeichnent, den der Besucher später zu Gesicht bekommt. Das Verwaltungssystem einer Webseite, das im Hintergrund liegt wird als Back-end bezeichnet.
PHP wird serverseitig und somit als Erstes ausgeführt. Der Ordner „root“ wird mit der Methode scandir() ausgelesen. Diese gibt einen Array mit den Inhalten des Verzeichnisses zurück. Um sicher zugehen, dass später beim Aufruf der Seite eine zufällige Anordnung passiert, wird bereits hier mit der Funktion shuffle() eine zufällige Reihenfolge der Array-Elemente programmiert.
Dieser Array $retval wird nun mit einer foreach-Schleife durchlaufen und von jedem Element im Array wird das Dateiformat bestimmt. Dabei hilft die Methode pathinfo().
$ext = pathinfo($value, PATHINFO_EXTENSION);
Nun kann mit einem if-else Statement abgefragt werden worum es sich bei jedem einzelnen Element in der Schleife handelt.
if ($ext == "jpg" || $ext == "jpeg" || $ext == "gif" || $ext == "png") { … }
Wenn es sich also um eine Bilddatei handelt, dann soll eine Miniatur des Bildes ausgegeben werden. Dazu benützen wir die print-Methode. Sie dient dazu um aus PHP Variablen oder Strings auf die HTML-Bühne zu „drucken“.
print "<... class='thumb' src='" . PATH . "/" . $value . "'/>";
$value ist dabei das entsprechende Element in der Schleife. PATH gibt den absoluten Pfad zur Datei an.
Selbiges passiert mit allen anderen Dateiformaten. Hierbei kann jedes beliebige Dateiformat abgefragt werden und somit könnte diese Mikro-Seite auf weitere Formate ausgebaut werden.
Wenn es sich beim gerade durchlaufenen Element um eine Textdatei handelt, wird deren Inhalt ausgelesen und in einem Div-Container auf der HTML-Bühne platziert.
$lines = file_get_contents(PATH . '/' . $value);
$lines = str_replace("\n","¶",$lines);
print "" . nl2br($lines) . "";
Mit der Methode file_get_contents() kann mit wenig Mühe der Inhalt (ein String) der Text-Datei abgefragt werden. Dieser String wird der Variable $lines zugewiesen. Aus kosmetischen Gründen kann hier noch mit str_replace() jeder Zeilenumbruch in ein Paragraphen-Symbol verwandelt werden. nl2br() wandelt PHP „\n“ Umbrüche in echte HTML Umbrüche um.
Um auch mit Ordnern arbeiten zu können, kann jedes Schleifen-Element auch ganz leicht auf „kein Dateiformat“ abgefragt werden.
else if ($ext == "") {
Wenn also kein Format existiert handelt es sich zwangsläufig um ein Verzeichnis.
Wenn dem so ist, wird wieder mit print ein Hyperlink mit der absoluten Pfadangabe zum Subverzeichnis ausgegeben.
Dazu bringen wir eine neue Konstante QUERY ins Spiel. Query dient dazu, um dem Link ein ?p= vor die eigentliche Pfadangabe zu hängen. Somit kann am Anfang des Scripts mit if(isset($_GET['p'])){ erfragt werden in welchem Verzeichnis sich der User gerade befindet.
<... href='" . QUERY . PATH . "/" .$value."'>
wird zu ?p=root/pfadangabe/aktuelle-Position-in-der-Schleife.format
Breadcrumbs - Brotkrümel
Um Besuchern der Webseite eine bessere Übersicht über einzelne Ordner und Dateisysteme des Portfolios zu gewähren, bauen wir noch eine Brotkrümel-Navigation ein. So kann im Portfolio leicht vor und zurück navigiert werden.
Übersicht
$crumb = explode("/", PATH);
if (PATH != 'root' && realpath(PATH)) {
print "…div class='breadcrumbs'>";
$newpath = '';
foreach($crumb as $index => $value) {
$newpath .= $value;
if($index < count($crumb)-1)
print "…a href='" . QUERY . $newpath ."'>$value > ";
// last item //
else
print $value;
$newpath .= '/';
}
print "…div>";
}
Die Variable $crumb stellt dabei einen Array dar, der jeden einzelnen Pfadabschnitt unseres Dateisystems beinhaltet. Mit der Methode explode() kann hier leicht unsere Pfadkonstante PATH bei jedem „/“ getrennt werden und als Element in den Array $crumb gegeben werden.
$crumb = explode("/", PATH);
Um die einzelnen Elemente wiederum auszugeben, durchlaufen wir den Array mit Hilfe einer foreach-Schleife. Um sicher zu gehen, dass jeder Brotkrümel-link auch auf den richtigen Pfad verweist, behelfen wir uns hier mit einer weiteren Variable $newpath.
Ihr wird pro Schleifendurchlauf der aktuelle Schleifenwert zu-addiert. Somit wächst der String in dieser Variable pro Schleifendurchlauf um das aktuelle Element und beinhaltet somit immer den aktuellen Gesamt-pfad.
$newpath .= $value; // .= Addition/Zuweisung
Um den User nicht zusätzlich zu verwirren und die Brotkrümelnavigation zu perfektionieren soll der letzte "Krümel" keinen Link darstellen und auch keinen weiteren > (Pfeil nach rechts) anzeigen. Der letzte "Krümel" zeigt ja das aktuelle Verzeichnis an und soll somit nicht auf sich selbst verlinken.
Die foreach-Schleife bietet eine sehr praktische Möglichkeit die aktuelle Schleifenzahl als Schlüssel direkt in eine Variable zu speichern.
foreach($crumb as $index => $value) {
Es wird also der Array $crumb durchlaufen, die aktuelle Schleifennummer wird in die Variable $index gespeichert und der Wert des aktuellen Schleifenelements wird in die Variable $value gespeichert. $index trägt nun bei jedem Schleifendurchlauf den aktuellen Schleifenwert und somit kann auf einfach Weise erörtert werden ob es sich um ein beliebiges Element in der Schleife handelt oder um das Letzte.
if($index < count($crumb)-1)
Die Methode count gibt die Anzahl an Arrayelementen in der Variable $crumb zurück. Solange die $index Variable also kleiner ist als die Gesamtzahl an Elementen weniger eins soll jeder Brotkrümel als Link zum jeweiligen Verzeichnis ausgegeben werden. Trifft diese Abfrage nicht zu handelt es sich um das letzte Element und es wird kein Link ausgegeben.
print "<... href='" . QUERY . $newpath ."'>$value > ";
Aus kosmetischen Gründen kann dieser gesamte Codeblock in ein if-Statement gepackt werden, das sicherstellt, dass das root-Verzeichnis (in unserem Fall /root) nicht ausgegeben wird.
if (PATH != 'root' && realpath(PATH)) {
Also nur wenn der User in ein Subverzeichnis klickt werden die Brotkrümel ausgegeben.
Die Variable/Konstante QUERY
Die Variable QUERY hält den sogenannten query-string ?p= (p ist variabel, steht für Pfad) der es uns ermöglicht mit der Funktion isset() festzustellen, ob eine URL einen solchen query-string enthält.
http://en.wikipedia.org/wiki/Query_string
http://php.net/manual/en/function.isset.php
An den Anfang unseres PHP Scripts stellen wir nun folgende Zeilen:
if(isset($_GET['p'])) {
if (preg_match('#(\./|\.\./|~/|\\\)#', $_GET['p']) || !realpath($_GET['p'])) {
print "<…div class='message'>";
print "directory is forbidden!";
print "<…div>";
} else if ($_GET['p'] == '') {
define(PATH, "root");
} else {
define(PATH, $_GET['p']);
}
} else { define(PATH, "root"); }
//
define(QUERY, "?p=");
Mit if(isset($_GET['p'])){ überprüfen wir als Erstes ob überhaupt ein ?p= in der URL vorhanden ist. Wenn dem so ist, speichern wir diesen Wert in die Konstante PATH.
Aus Sicherheitsgründen können wir es neugierigen Besuchern noch erschweren in der Ordnerhierarchie nach „oben“ zu wandern. Wie wir wissen sorgt ein einfaches ../ in einer Pfadangabe dafür, ein Verzeichnis darüber zu wählen. Um möglichst allen Möglichkeiten eines "hacks" auszustellen ist hier ratsam mit sogenannten Regular Expressions zu arbeiten. Regular Expressions oder kurz regex bieten die Möglichkeit Zeichenketten anhand bestimmter Regeln zu filtern. Da viele dieser regex-Ausdrücke sehr kompliziert erscheinen ist es ratsam im Internet nach vorgefertigten Regeln und Ausdrücken zu suchen und diese nach Möglichkeit abzuwandeln oder direkt zu verwenden. In unserem Fall ist der reguläre Ausdruck noch recht einfach nachvollziehbar.
Mit Hilfe der Methode preg_match kann in PHP ein regex auf einen String angewendet werden.
if (preg_match('#(\./|\.\./|~/|\\\)#', $_GET['p'])
Das erste Argument der preg_match Methode beschreibt den Suchstring (also den regulären Ausdruck) und das zweite Argument steht für das zu-durchsuchende Element. In unserem Fall soll der Pfad $_GET['p'])durchsucht werden auf #(\./|\.\./|~/|\\\)#
Wie in den meisten bekannten Script und Programmiersprachen beschreibt der Operator | ein oder. Der Punkt . ist ein reserviertes Zeichen innerhalb von Regular Expressions. Wenn nach einem Punkt innerhalb eines Strings gesucht werden soll muss das reservierte Zeichen "escaped" werden. Dazu wird in PHP und in Regular Expressions generell ein Backslash \ verwendet.
#(\./|\.\./|~/|\\\)# kann in seine Bestandteile zerlegt werden und so besser verstanden werden.
#(\./|\.\./|~/|\\\)# es wird überprüft ob die Pfadangabe die Zeichenfolge ./ oder ../ oder ~/ oder \\\ enthält.
Wenn preg_match true zurück gibt wird, also einer der überprüften Strings in der Pfadangabe gefunden wird soll eine Fehlermeldung für den User ausgegeben werden.
print "<…div class='message'>";
print "directory is forbidden!";
print "<…div>";
Wenn keiner der Zeichenketten gefunden wurde wird unsere Konstante PATH auf den Pfad in der URL-Angabe gesetzt.
define(PATH, $_GET['p']);
Wenn generell kein ?p= in der URL gefunden wird, also kein Query String gesetzt ist wird die Konstante PATH auf "root" gesetz.
Im Überblick
…?php
if(isset($_GET['p'])) {
if (preg_match('#(\./|\.\./|~/|\\\)#', $_GET['p']) || !realpath($_GET['p'])) {
print "…div class='message'>";
print "directory is forbidden!";
print "…/div>";
} else if ($_GET['p'] == '') {
define(PATH, "root");
} else {
define(PATH, $_GET['p']);
}
} else { define(PATH, "root"); }
//
define(QUERY, "?p=");
// Brotkrümel
$crumb = explode("/", PATH);
if (PATH != 'root' && realpath(PATH)) {
print "…div class='breadcrumbs'>";
$newpath = '';
foreach($crumb as $index => $value) {
$newpath .= $value;
if($index < count($crumb)-1)
print "…a href='" . QUERY . $newpath ."'>$value > ";
// last item //
else
print $value;
$newpath .= '/';
}
print "…div>";
}
if (($retval = scandir(PATH)) !== false) {
$retval = array_filter($retval, 'filter_files');
shuffle($retval);
}
function filter_files($file) {
return ($file != '.' && $file != '..' && $file != '.DS_Store' && $file != 'Thumbs.db');
}
//Schleife - durch alle ausgelesenen Dateien iterieren
foreach ($retval as $value) {
$ext = pathinfo($value, PATHINFO_EXTENSION); //Dokumentformat
if ($ext == "jpg" || $ext == "jpeg" || $ext == "gif" || $ext == "png") {
print "…img class='thumb' src='" . PATH . "/" . $value . "'/>";
} else if ($ext == "txt" || $ext == "rtf") {
$lines = file_get_contents(PATH . '/' . $value);
$lines = str_replace("\n","¶…br/>",$lines);
print "…div class='thumb text'>" . nl2br($lines) . "…div>";
} else if ($ext == "pdf" || $ext == "doc" || $ext == "docx" || $ext == "xls" || $ext == "xlsx" || $ext == "pps" || $ext == "zip" || $ext == "rar") {
print "…div class='thumb file'>…a href='" . PATH . "/" . $value . "'>…img src='img/file.png'/>…span class='desc'>$value…span>";
} else if ($ext == "") { //Ordner, Verzeichnis
print "…div class='thumb folder'>…a href='" . QUERY . PATH . "/" .$value."'>…img src='img/folder.png'/>…span class='desc'>$value…span>";
} else {
//diese Dateiformate werden nicht unterstützt
//können aber jederzeit erweitert werden
}
}
…?>
Im Gegensatz zu PHP, das vor allem anderen direkt am Server ausgeführt wird, wird JavaScript (nicht zu verwechseln mit Java) client-seitig im Browser des Users interpretiert. Eine der beliebtesten Javascript Bibliotheken nennt sich jQuery.
Im folgenden Tutorial Abschnitt folgt eine kurze Übersicht über die Arbeitsweise mit jQuery.
Wie jede Javascript Bibliothek muss innerhalb des Quelltextes einer Webseite auf die Bibliothek verwiesen werden. Dies kann auf zweierlei Arten erfolgen. Das jQuery Projekt wird unter anderem auf Google-Code „gehosted“ und kann so direkt (immer als aktuellste Version) in die Seite eingebunden werden. jQuery kann aber auch als lokale Datei verlinkt werden. Dazu muss die jQuery.js Datei als erstes von der Webseite www.jquery.com geladen werden. Gleich wie jede JS Datei muss diese über in das aktuelle HTML (oder PHP) Dokument eingebunden werden.
…script type="text/javascript" src="js/jquery-1.4.min.js">
Das jQuery Bundle beinhaltet alle grundlegenden Javascript Anwendungsbereiche, allerdings gibt es neben der normalen jQuery Bibliothek noch ein weiteres Projekt namens jQuery UI (UI für User Interface). Diese Erweiterungsbibliothek ermöglicht es leichter Benutzeroberflächen zu programmieren. Für unsere Desktop-Metapher bietet jQuery UI genau die richtigen Methoden und Funktionen für Drag&Drop Anwendungen.
jQuery UI lässt sich unter www.jqueryui.com downloaden.
…script type="text/javascript" src="js/jquery-ui-1.8.1.custom.min.js">
Schlussendlich muss natürlich noch das eigene JavaScript in das aktuelle Dokument eingebunden werden.
…script type="text/javascript" src="js/scripts.js">
Um einen besseren Überblick über den Aufbau unseres Projekts zu bekommen, geben wir sämtliche JavaScript Dateien in ein eigenes „js“ Verzeichnis. (Selbiges gilt für CSS Dateien die wir in ein Verzeichniss „css“ geben)
Die Funktionsweise von jQuery
Den Vorteil den jQuery bietet, ist das Arbeiten mit CSS Selektoren innerhalb von Javascript. So kann ein HTML Element, z.B. eine Bilddatei mit $(“img“).machEtwas() angesprochen werden.
Wenn ein HTML Element eine bestimmte Klassenzuweisung oder eine ID besitzt, kann diese mit der gleichen Methode angesprochen werden.
HTML
CSS
#bezeichner { display : none }
jQuery
$(“#bezeichner“).css({ “display“ : “none“ });
jQuery bietet weiters die Möglichkeit mit vorgefertigten Methoden wie z.b. .hide() und .show() zu arbeiten. $(“#bezeichner“).hide(); macht in diesem Fall nichts anderes als $(“#bezeichner“).css({ “display“ : “none“ }); nur ist hide() um einiges kürzer in der Schreibweise.
When de DOM is ready …
jQuery bietet die $(document).ready(function(){ Funktion, die sicherstellt, dass alle Seiteninhalte bereits geladen sind bevor irgend ein Javascript Code ausgeführt wird.
Grundlegend wird jeder jQuery code in diese Funktion geschrieben.
$(document).ready(function(){
//hier folgt der Code
});
Bevor wir mit dem eigentlichen Codeabschnitt für unser Projekt in jQuery beginnen, werden wieder einige Variablen definiert.
Um sicherzustellen, dass alle Dateien unseres Miniportfolios auf unterschiedlichen Ebenen auf der Bühne liegen, definieren wir als erstes eine Variable z die für den z-Index jedes Elementes steht. Diese beginnt bei 0 und wird später beim Durchlauf durch alle Dateien jeweils um 1 erhöht. So wird sichergestellt, dass jedes Element einen anderen z-Index Wert hat.
var z = 0;
Da für unsere Desktop-Metapher kleine Miniaturbilder verwendet werden, definieren wir als erstes die Größe (Breite) der Miniaturen:
var small = '200px';
Beim MouseOver über ein Miniaturbild soll dieses auf auf die doppelte Breite animieren.
var full = '400px';
Wie jede Script- und Programmiersprache bietet auch jQuery eine Schleifenmethode mit der durch Arrays iteriert werden kann.
Jedes unserer HTML Elemente auf der Bühne hat einen Klassennamen “.thumb“.
Beim Ansprechen von .thumb liefert jQuery einen Array mit sämtlichen .thumb Elementen zurück. Jetzt kann mit der Methode .each() jedes Element gezielt angesprochen werden.
$(".thumb").each(
function() { …
Innerhalb der .each() Schleife soll sichergestellt werden, dass jedes Element eine zufällige Position innerhalb des Browserfensters zugeteilt bekommt. JavaScript Math.random() liefert eine Zufallszahl zwischen 0 und 0,999. Diese kann mit sowohl mit der Höhe des Fensters $(document).height() als auch mit der Breite $(document).width() multipliziert werden, um so eine beliebige Position innerhalb der Bühne zu bekommen. Da der zufällige Punkt immer die linke obere Ecke eines Elements beschreibt können wir noch grob 400px von der Browserbreite und Browserhöhe abziehen.
WICHTIG: Auch die Berechnung dieser Zufallspositionen muss innerhalb der .each() Schleife passieren, um gewährleisten zu können, dass bei jedem Durchlauf durch ein Element eine neue Zufallsposition generiert wird.
var l = Math.floor(Math.random() * ($(document).width()-400));
var t = Math.floor(Math.random() * ($(document).height()-400));
Als letztes muss jedem Element diese neue Zufallsposition zugeteilt werden.
$(this).css("left", l + 'px');
$(this).css("top", t + 'px');
Nun kann die .each() Schleife geschlossen werden.
Drag&Drop
Im nächsten Schritt kommt jQuery UI zum Einsatz. jQuery UI bietet unter anderem die einfache Methode .draggable() die auf ein Element angwendet werden kann, um dieses mit Drag&Drop Eigenschaften auszustatten.
$(".thumb").draggable({ containment: "window" });
Sobald $(".thumb").draggable(); im JS Code definiert ist lassen sich sämtliche Elemente die die Klasse .thumb zugewiesen haben über die Bühne ziehen. Zusätzlich bietet die Methode .draggable noch ein einen sehr praktischen Parameter namens containment. Ihm kann sowohl ein container (z.B. ein div) aber auch ein String wie z.B. "window"zugewiesen werden - mit "window" ist das aktuelle Browserfenster gemeint, also genau das was für unser Vorhaben benötigt wird.
Vergrößern der Miniaturbilder bei MouseOver
Wenn der User mit der Maus über ein Miniaturbild auf der Bühne fährt, soll dieses auf die doppelte Breite (400px) vergrößert werden. Beim Verlassen des Bildes mit der Maus soll die ursprüngliche Größe (200px) wieder hergestellt werden. jQuery liefert dafür eine passende Funktion .hover(). Diese Funktion besteht aus zwei Teilen, dem ersten MouseOver und dem zweiten MouseOut.
$(".thumb").hover(
function () {
//Was soll passieren bei MouseOver
},
function () {
//Was soll passieren bei MouseOut
}
}
Um dem User nicht ein abruptes Vergrößern der Miniaturen zu präsentieren, werden wir die Vergrößerung von klein auf groß animieren. Dafür hält jQuery wieder eine einfache aber sehr mächtige Funktion .animate() bereit, mit der so gut wie jede CSS Eigenschaft eines Elements auf einer Webseite animiert werden kann.
Im ersten Teil der .hover Funktion vergrößern wir auf die Variable full.
$(this).stop().animate({"height": full}, "fast");
Die Variablen full und small wurden anfänglich in unserem jQuery Code definiert.
Da wir allerdings nicht nur Bildmaterial in unserem Portfolio unterstützen sondern auch Textdateien und andere Formate müssen wir noch eine Ausnahme hinzufügen. Klassen, die NICHT auf die Animation anspringen sollen.
Die jQuery .not() Methode macht genau das. Außerhalb der .hover() Funktion können wir wieder eine Variable definieren, die all unsere Klassennamen enthält die nicht auf den Vergrößerungseffekt anspringen sollen.
$formats = '.text, .file, .video, .audio, .folder';
Dann setzen wir ein .not($formats) direkt vor die .animate() Funktion. So ist sichergestellt, dass alle .thumbs Elemente auf die .hover() Funktion ansprechen, allerdings nicht alle Elemente einen Vergrößerungseffekt zugeteilt bekommen. Dieser bleibt den Bildelementen vorbehalten.
Ein weiterer wichtiger Schritt innerhalb von .hover() ist das Erhöhen der anfänglich definierten z-Variable. So wird bei jedem MouseOver über ein Bühnenelement dieses um eine z-Index Ebene nach oben gesetzt.
Kosmetische Korrekturen und Feinheiten
Die Drag&Drop und die .hover() Eigenschaft der Miniaturbilder sorgt leider für eine kleine „Unschönheit“ im Userinterface unserer Webseite. Bei schnellen Mausbewegungen und gedrückter Maustaste über einem Bild, verlässt die Maus oftmals für sehr kurze Zeit das Miniaturbild und im nächsten Augenblick kommt schon wieder erneut die .hover() Funktion zum Einsatz. Dies führt zu einem leichten und schnellen Aufblitzen (Verkleinern und erneutes Vergrößern) der Bilder.
Um diesem „Bug“ entgegenzuwirken, deaktivieren wir einfach die .hover() Eigenschaft der Miniaturen bei einem Klick auf ein Miniaturbild. So wird während einem „Drag“ eines Objektes keine .hover() Funktion gefeuert. Erst beim Loslassen der Maus wird die .hover() Funktion wieder aktiviert.
Um eine Funktion zu deaktivieren nehmen wir die jQuery .bind() Funktion zur Hilfe. Sie ermöglicht es Event-Handler (wie z.B. .hover(), .mousedown(), .mouseup() oder .click()) an einen Selektor zu binden. So binden wir auf $(".thumb") einen mousedown Handler (gleich einem Click Handler) der sicherstellt, dass bei Klick auf ein Element, und somit dem eigentlichen Beginn des Drag-Ereignisses, die .hover() Eigenschaft eines jeden Miniaturbildes deaktiviert ist. Erst bei einem .mouseup() an einem Element soll die .hover()-Eigenschaft an alle Elemente gebunden werden.
$(".thumb").bind( "mousedown", function() {
$('.thumb').unbind('mouseenter mouseleave');
});
$(".thumb").bind( "mouseup", function() {
bind_hover();
});
Die gesamte .hover() Funktion packen wir daher einfach in einen normalen Funktionsaufruf den wir bind_hover() nennen.
Verhalten eines Ordners
Da unsere Desktopmetapher so perfekt wie möglich werden soll, müssen auch Ordner so gewöhnlich wie möglich funktionieren. Dafür bietet wieder jQuery die passende Methode .dblclick(), die es möglich macht Funktionsaufrufe mit einem Doppelklick zu feuern.
Da jeder Ordner ein normaler HTML Hyperlink ist, muss das normale Linkverhalten eines jeden unterbunden werden. .preventDefault() verhindert das normale Linkverhalten und einen neuen Seitenaufruf bei Klick auf einen Ordner.
Als kleiner "bugfix" kann hier noch auch bei Klick der z-index um eine Ebene nach oben gesetzt werden. Dieser Trick kann z.B. beim Verlieren des Fokus des Browserfensters von Vorteil sein.
$('.folder a').click(function(e) {
$(this).css('z-index', z);
z++;
e.preventDefault();
});
Somit steht einem Doppelklick-Event auf einen Ordner nichts mehr im Wege. Da der Hyperlink eines Ordners bereits auf den richtigen Pfad dieses Ordners verweist, kann mit der Methode .attr() das href Attribut des Links verwendet werden und mit window.location.href() der Aufruf dieses Ordners gefeuert werden. Im Detail sieht das so aus:
$('.folder a').dblclick(function(e) {
window.location.href = $(this).attr("href");
});
Cascading Stylesheets werden im der Webseite eingebunden.
…link rel="stylesheet" type="text/css" href="css/style.css" media="screen, projection" />
Wie unsere Javascript-Dateien, die wir im Ordner „js“ finden, geben wir auch unsere css-Dateien in ein Subverzeichnis namens „css“. Dies dient in erster Linie der besseren Übersicht über unser Webprojekt.
Die Gestaltung
Der body der Webseite. Grundlegend wird hier definiert, dass die Seite einen weißen Hintergrund hat (#fff), keine Seitenränder besitzt (margin), eine monospace-Schriftfamilie gewählt wird und die Schriftgröße auf 12px gesetzt wird.
body {
background:#fff;
margin:0;
font-family: 'Lucida Console', 'Monaco', monospace;
font-size:12px;
}
Als nächstes können weitere elementare Eigenschaften der Webseite definiert werden - die Linkstyles:
a:link, a:visited {
color:#fff;
text-decoration:underline;
}
a:hover, a:active {
color:#fff;
text-decoration:line-through;
}
:focus, *:focus {
outline: 0;
}
Bei der Eigenschaft :focus handelt es sich um eine CSS-Pseudoklasse.
Die .thumb Klasse - Style jedes Elements
.thumb {
height:200px;
margin:0;
float:left;
position:absolute;
cursor:move;
}
Da eine Drag&Drop Eigenschaft der Elemente voraussetzt, dass jede Komponente eine fixe Position innerhabl des HTML-bodys hat setzen wir die Eigenschaft "position" auf "absolute. Zusätzlich geben wir jedem Element noch ein cursor:move Attribut, damit der User auf den ersten Blick leicht erkenne kann, dass es sich beim aktuellen Element um ein "ziehbares" handelt.
Als nächstes definieren wir die Ausnahmen und spezifischen Merkmale der jeweilig-ausgelesenen Formate.
Somit bekommt eine ausgelesene Textdatei die Klasse .text zugewiesen:
.text {
background:yellow;
padding:20px;
overflow:hidden;
max-width:500px;
white-space:nowrap;
height:auto !important;
}
Wichtig hierbei ist, dass jedes "Textfeld" eine automatische Höhe mit "height:auto" zugeteilt bekommt.
Jedes Textfeild unterstützt sowohl Links als auch andere HTML Attribute. Somit kann innerhalb einer ausgelesenen Textdatei z.b. eine Linkliste ausgegeben werden. Damit auch diese Links innerhalb eines Textfeldes ordnungsgemäß gestyled sind schreiben wir folgendes:
.text a:link, .text a:visited {
color:#000;
text-decoration:underline;
}
.text a:hover, .text a:active {
color:#000;
text-decoration:line-through;
}
Jeder Ordner in unserem "Mini-Portfolio" hat die Klasse .folder zugeteilt bekommen:
.folder {
width:230px;
height:10px;
color:black;
}
.folder img {
border:none;
margin-left:-10px;
}
.folder a {
cursor:default;
}
Um vom Interface einem Betriebsystem und somit bekannten Verhaltensregeln möglichst ähnlich zu sein, soll jeder Ordner einen normalen Mauszeiger zugeteilt bekommen - so wie es der durchschnittliche User von einem Betriebsystem wie Windows, Mac Os oder Linux gewohnt ist.
Handelt es sich beim ausgelesenen Element um eine unterstützte Datei wie z.B. ein .pdf oder ein .doc so kommt die Klasse .file ins Spiel.
.file {
width:160px;
height:10px;
color:black;
}
.file img {
border:none;
height:206px;
}
Da Ordner und Dateien nicht nur ein Symbol abbilden sollen sondern auch den Namen darunte damit klar wird um was es sich denn überhaupt handelt, hat jeder Ordner und jede Datei unterhalb des Symbols ein span-Element angehängt das den Namen der Datei trägt. Diese span-Element hat die Klasse .desc zugewiesen bekommen.
.desc {
background:#fff;
padding:5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
line-height:20px;
}
Mit CSS3 wurde erstmals die Möglichkeit eingeführt mit purem CSS abgerundete Ecken auf Elemente anzuwenden. Derzeit unterstützen nur eine limitierte Anazhl von Browsern abgerundete Ecken.
Das Webkit Projekt auf dem z.B. Apples Safari aufbaut verlangt ein -webkit-border-radius und Mozilla Firefox verlangt ein -moz-border-radius um einem Element runde Ecken zu geben.
Brotkrümel-Links
Da es sich bei der Brotkrümelstruktur um simple Text-Hyperlinks handelt reicht es die Textfarbe der Links zu definieren. Schriftart und Schrift wurde übergreifend in unserem body-Selektor definiert. Das !important Attribut überschreibt bereits vorher definierte Eigenschaften.
.breadcrumbs a{
color:#000 !important;
}