Journal: Neueste Artikel erscheinen hier (Seite 8 von 21)
Javascript Library Builder

JS-Build
Es gibt einige Methoden Javascript auf HTML-Seiten einzubinden. Ein Block im <body>, in onclick-Attributen und ähnlichem, oder als Verknüpfungen im <head> aber am besten in einer externen Datei, die nach dem HTML-Dokument geladen wird. Nur will man beim Entwickeln die einzelnen Javascript-Teile meist in getrennte Dateien legen und auf der Seite dann möglichst viel in eine (am besten möglichst kleine) Datei packen, um Requests zu sparen. Dieses Problem kann der Javascript Library Builder lösen, ein recht kurzes Shell-Script, welches eine Sammlung von .js-Dateien in wenige Dateien minimiert.
Man nehme zum Beispiel eine solche Dateistruktur:
lib/
php/...
js_frontend/
00_jQuery.js
01_jQ_plugin.js
02_effekte.js
licence.txt
js_backend/
03_ajaxCalls.js
Der Scriptaufruf wäre so einfach wie:
jslibbuild.sh -o build lib/js*
Ich habe auf dieser Seite 27 einzelne Dateien, die ich in zwei Javascript Dateien packe, nämlich für die Seite und für das CMS. Diese Beispiel-Dateistruktur würde jetzt in den zwei Dateien js_frontend.min.js und js_backend.min.js im Ordner build resultieren. Der Datei js_frontend.min.js würde zusätzlich nach dem minimieren mit jsmin die Datei licence.txt vorgehängt, sodass z.B. in Kommentaren (die von jsmin geschluckt werden) vermerkte Autorenhinweise erhalten bleiben, was unter anderem bei den CC-Lizenzen nötig ist.
Dazu akzeptiert das Script die optionale Option -l nach der der Name der Lizenz-Dateien angegeben wird. Eine weitere optionale Option ist -c, um das build-Verzeichnis vor dem Anlegen der neuen Dateien zu löschen. Das ist nötig, wenn ein ganzer source-Ordner gelöscht wird, aber dringend zu vermeiden, wenn weitere Dateien im build-Ordner liegen. Hier noch ein Beispiel:
jslibbuild.sh -c -l gpl.txt -o /srv/www/htdocs/js ~/web/lib/js/*
Das Script benötigt jsmin, steht unter GPLv2+ und kann hier heruntergeladen werden:
Zum „installieren“ einfach in den Ordner ~/bin kopieren. Das Script ist eigentlich ziemlich einfach, kann aber doch einiges an Arbeit ersparen.
My MySQL API onion for PHP

MySQL Onion
A huge part of web applications is usually the interaction with the SQL database. This is why I want as little work as possible connecting, escaping values, getting the right tables an so on in PHP. But it should stay simple and allow modular approaches. Therefor I'm using some nested APIs for doing queries easily:
PDO
The very fist thing I am using is PDO. It can handle many RDBMS, but I am most of the times using MySQL or SQLite. By using PDO as an API for the following layers I can make sure most of the code will work for many RDBMSs. PDO even simplifies transactions and prepared statements. Here's some sample PHP code using PDO:
$pdo=new PDO('mysql:host='.$host.';dbname='.$db, $user, $passwort);
$pdo->exec('UPDATE test SET foo="bar" WHERE id=4');
$satement=$pdo->prepare('SELECT * FROM blogeintraege WHERE id=:id');
$satement->bindValue(':id',3,PDO::PARAM_INT);
$satement->execute();
$data=$satement->fetchAll();
PDO Simplifier
The next layer is a class that will hold a MySQL database Connection (a PDO Object) and offer some simple functions for doing e.g. a simple prepared statement. Instead of binding each values manually, you can throw an array in.
It also includes a cache, if you want to run statements more than once. It can append a prefix to all queried tables and checks dynamically inserted tables for validity to avoid SQL-injections and MySQL errors. It is used like that:
$res=$db->sql("SELECT * FROM blogeintraege");
$res=$db->sql(
"SELECT * FROM #test WHERE id=:id",
array('id'=>$id),array('id'=>PDO::PARAM_INT),
array('test'=>'blogeintraege'),
array('limits'=>array(0,$l),'buffered'=>false)
);
For one array element this does not look too tiny, but the more values are bound, the more useful it gets. And it is very useful if you already have your values in an array, like $_GET.
Note that nearly everything is optional. The table array can contain more tables, for example you can have an array of tables for different languages, if they are in different tables. The bind-types don't need to be specified too. You can even leave out everything except the query as shown in the fist line of code. The Result will by default be returned as a nice array (the GROUP_CONCAT fields are array'ed too) but you can use all other PDO fetch types.
This layer follows a rather functional approve, so I needed another layer for accessing the central sql()-Function in an OOP manner. This should avoid some runtime errors and you can modify the SQL in a modular system.
Statement builder
So I created a wrapper object, that holds a pointer to the database and will construct the parameters for sql(). This comes in handy as more and more optional parameters are added.
The PDO Simplifier has a method to build such statement-objects called sqlO(). This is how the wrapper is used:
$db->sqlO('INSERT INTO blogtaglinks SET ##,type=3')
->setSet(array('ID_tag'=>$lasttagid,'ID_entry'=>$id))
->exec();
$res=$db->sqlO("SELECT * FROM #test WHERE id=:id")
->setData(array('id'=>$id))
->setDataTypes(array('id'=>PDO::PARAM_INT))
->setTables('test'=>'blogeintraege'),
->setLimits(0,$l)
->setBuffered(false)
->exec();
);
As you can see, it is a little more code, but the code is pretty self-explanatory and now one can build the sets and the other parameters as arrays and then include them easily in the statements.
A bit different: Zend Framework's $db->select() approach
A next step would be to build queries with a single API. This is a feature implemented by the Zend Framework, where you can build your SQL with some API functions and it will even work across various databases:
select = $db->select()
->from('blogeintraege',array('id','Titel'))
->where('id < ?', $id)
->order('id DESC')
->limit(0,10);
Well doesn't that look nice?
Blogpopst-Previews

Blogpost Tooltips
Heute hatte ich mal wieder einen Einfall, was meinem Blog noch fehlt, also außer dem Refactoring der MySQL API. Irgendwie nicht zufriedenstellend waren nämlich die Post-Listen in der Sidebar, da durch das Datum neben dem Titel kaum eine Überschrift in eine Zeile gepasst hat. Nun habe ich das Problem „gelöst“, indem bei Mouseover ein Tooltip mit Meta-Infos angezeigt wird.
Das Ganze läd von einer simplen PHP-Schnittstelle mit AJAX bzw. „AJAJ“ (J für JSON) die Metadaten, also die Anzahl der Kommentare und die Tags, aber auch einen kleinen Textausschnitt („Teaser“). Mit jQuery geht das recht fix und mit wenig Code. Auch die Anzeige als Tooltip war recht einfach. Die runden Ecken werden im Firefox mit -moz-border-radius gemacht und auch die Transparenz wird von der CSS-Eigenschaft opacity geregelt, sodass kein weiteres Hintergrundbild nötig ist. Mit if ($(bla).width()<400) wird verhindert, dass bei genug Platz das Datum entfernt wird, zu sehen auf der Seite Archiv. Dank jQuery bleibt es bei 29 Zeilen JS-Code.
Auch der PHP-Teil ist recht simpel und besteht eigentlich nur aus einer SQL-Abfrage und der Funktion json_encode(), das sind dann 16 Zeilen.
Jetzt bin ich nur gespannt, wie sich das auf den Traffic bzw. die Reqeusts auswirkt, da jedes mal, wenn jemand über einen Link fährt, ein Request an den Server gesendet wird.
Achja, bisher gab es auch keine ausgefeilten 404-Seiten, aber jetzt gibt es eine Fehlerseite, die z.B. auch einen Link zur Suche anbietet.
Update 2009-08-01
Ich habe jetzt auch noch meine Lightbox an das Look & Feel der Blogpopst-Previews angepasst, sodass sie jetzt nicht nur individuell, sondern auch (im Firefox) gut aussehend ist. Außerdem läd sie jetzt keine Graphiken mehr, nur um „prev“, „next“ und „close“ anzuzeigen. Zu testen hier:
Obwohl ich es eigentlich nicht so mag, in jQuery Plugins herumzubasteln, habe ich doch eine ganze Passage gerefactort und hoffe jetzt einfach mal, dass es auch im IE noch halbwegs klappt.
Twitter Bookmarklet III
For twitter users: Here's an easy-to-use toolbar button for your browser that substitutes the URL shortening and copy-pasting for you. There's no installation, I don't want to know your twitter login or password, and it will shorten the URL using bit.ly.
The bookmarklet will:
- Receive a short URL from the bit.ly API
- Open up your twitter homepage in a new tab (Firefox) or in a pop up with the short URL and the page title included in the textarea
- (Or take you to the twitter login page, which will then redirect)
To install just drag this link/button into your browser's bookmarks toolbar:
The bookmarklet is even supporting flickr-Photos (using their short URL like http://flic.kr/p/6qxGR2) and other web sites (Ars technica, PHP-Manual, this blog...) if they provide own shortening services.
The code is a bit inspired by John Resig's „retweet“ button but it's not on the page you are viewing, but in your browser's toolbar, so you don't rely on webmasters cluttering their designs with social bookmarking services' buttons.
For IE-Users: You will have to right-click on the link and choose save bookmark. After that, you will be warned, because it's not a simple link, but a bookmarklet.
MacMahonMosaik Online Game

Mac Mohan Mosaik
Da ich beim Känguru-Wettbewerb 2009 mitgemacht habe, habe ich auch das MacMahonMosaik in die Hände bekommen. Es ist ein kleines Rätsel ähnlich wie Sudoku. Weil es interessant zu Modellieren ist, habe ich das MacMahonMosaik als Online-Spiel erstellt. Hier ein paar Details zu Implementierung:
Modell
Jedes Quadrat im Spiel hat 4 Kanten, die in 3 verschiedenen Farben markiert sein können. Daher lässt sich jede Anordnung als 4-Tupel einer 3-Menge auffassen. Diese 81 Tupel wiederum können den natürlichen Zahlen von 0-80 zugeordnet werden. Somit habe ich als Objekte zunächst die 24 Quadrate (die anderen fallen weg, da sie durch Drehung erreicht werden können), die jeweils eine Zahl speichern. Sie müssen sich nun z.B. drehen können. Dazu wird die Zahl in das Tupel umgerechnet und die Einträge des Tupels um eine Stelle verschoben, wobei der letzte Eintrag der erste wird. Um zu Überprüfen, ob zwei Quadrate aneinander passen, dreht man eines der beiden zweimal und schaut dann einfach ob in der gewünschten Richtung die selben Farben stehen. Dadurch sieht die Prüffunktion im Javascript sehr kurz aus:
p.checkMatch=function(other,pos){
var mycodes=this.getColorCodes(); // Tupel aus Zahl
var o=other.clone(); // Neues Quadrat mit selber Zahl
var othercodes=o.rotate().rotate().getColorCodes(); // anderes Q. 2x drehen
return (mycodes.charAt(pos)==othercodes.charAt(pos)); //prüfen
}
Zusätzlich haben die Quadrate noch ein paar Darstellungsrelevante optionale Eigenschaften und Methoden. Ist ihnen ein <Canvas>-Element im HTML-Baum delegiert, können sie ihm die passenden Event-Handler für das interaktive Drehen und Bewegen zuweisen und eine graphische Repräsentation ihrer selbst zeichnen. Und sie speichern einige Daten für drag & drop.
Doch beim Ziehen und Ablegen kommt das zweite Objekt ins Spiel: Das Feld in dem die Quadrate abgelegt werden können. Wann immer man ein Quadrat bewegt, frag dieses Quadrat beim Gitter nach, ob es sich einrasten kann. Das Gitter gäbe dann die Pixel-Koordinaten des Einrastpunkts auf dem Bildschirm und die Koordinaten innerhalb des Gitters zurück. Wird das Quadrat dann fallen gelassen, registriert es sich im Gitter.
Das Gitter hat dazu ein zweidimensionales Feld hinterlegt, in dem es Pointer zu den abgelegten Quadraten speichern kann. Wenn jetzt ein Quadrat im Raster abgelegt wird und sich registriert hat, weist es das Raster an, sich zu revalidieren - Das Gitter ruft für jedes Quadrat und je seine vier Nachbarn die Prüffunktion auf. (Da das „Passen“ symmetrisch ist, ließe sich die Komplexität des Algorithmus vielleicht noch optimieren, doch das hätte wieder mehr Code zur Folge und bei 24 Einheiten...) Da das Gitter nur Zeiger zu den Quadraten speichert, ist bei einer Drehung eines Quadrats keine weitere Registrierung nötig. Falls also ein Quadrat angeklickt wird, rotiert es sich, aktualisiert die eigene Darstellung und gibt den Revalidierungsbefehl an das Raster.
Für die Darstellung hat das Gitter auch eine recht einfache Methode, die den Feldhintergrund rötlich färbt, sollte ein Fehler vorliegen und eine Gratulation meldet, sollten alle Quadrate an einem passenden Ort sein, also das Spiel gewonnen.
Ablaufdiagramm
Hier mal ein kleiner Flowchart. Man beginne das Lesen bei den Event-Handlern: (erstellt mit U+2500-U+257F: Box Drawing)
Quadrat
├ Zahl ◁──────┐ {Umrechnung}
├ (Tupel) ◁───┘
├ Drehen() ◀────────┐◁──┐─┐▷─────┐
├ Prüfen(Quadrat) ──◆───┊─┊──────┊──┐
├ [Darstellung] │ │ │ │ │
│ ├ Visualisieren◁─┊───┊─┘ │ │
│ └ [Handler] │ │ │ └──┐
│ ├ Klick ──────┊───┘ │ │
│ ├ Packen ────┊────────────┊──┐ │
│ ├ Bewegen ◀───┊───┐ │ │ │
│ └ Ablegen ────┊─────────┬▷─┤ │ │
└ Kopieren() ►──────┘ │ │ │ │ ▼ bool
[XY,XY] │ │ │ │
Gitter │ │ │ │ │
├ Feld[X,Y] │ │ │ │ │
├ KoordinatenBei(XY) ───┘ │ │ │ │
├ Registrieren(Quadrat) ◀─XY─┘ │ │ │
│ └ Un-Registrieren() ◀─────XY───┊──┘ │
├ Alle Prüfen() ►────────┐─▷────│─────┘
└ Darstellung erneuern() ─┘ ◁───┘
└ Färben(), Gratulation()
Wie das Gitter überprüft, ob auch am Rand rote Kanten liegen? Statt weiteren Code für den Rand zu basteln, wird das Gitter mit voll-roten Quadraten ohne graphische Repräsentation außerhalb das Gitters vorbelegt. Das hat den kleinen Nebeneffekt, das auch out-of-bounds-Fehler im Prüfalgorithmus vermieden werden, da ja z.B. bei negativen Gitterkoordinaten -1 stets ein solches „virtuelles“ Quadrat liegt.
Wie man also sieht, kann man an diesem Spiel schon einige lustige Code-Spar-Methoden benutzen. Eigentlich sparen sie nicht nur Code, sondern auch Nachdenken, wenn man sie „sieht“.
Javascript Umsetzung
JS-Closures habe ich in letzter Zeit immer mehr zu schätzen gelernt. (Man muss in PHP übrigens auch nicht mehr lange darauf verzichten) Sie lassen den Programmierer Funktionen, also mehr oder weniger Code, wie ein String oder eine Zahl an andere Funktionen übergeben oder in Variablen spichern, sodass mit anonymen Funktionsobjekten als Closures in JS eigene Kontrollstrukturen definiert werden können, wie diese zweifache for-Schleife, um über Koordinaten bzw. Zweidimensionales zu loopen:
function loopXY(w,h,cb) {
for (var x=0;x<w;x++) {
for (var y=0;y<h;y++) {
cb(x,y);
}
}
}
var m=[];
loopXY(5,7,function(x,y){
m.push("("+x+","+y+")");
});
alert(m);
Wie man sieht stehen in Javascript in den Closures alle äußeren Variablen zur Verfügung. Das wiederholte verwenden des Namens einer äußeren Variable führt trozdem noch dazu, dass in der Closure diese lokal verwendet wird und außen der alte Wert erhalten bleibt. Ein bischen gewöhnungsbedürftig ist die Verwendung von this in JS. Im oben gezeigten Code würde z.B. in der Schleife this auf window zeigen. Das lässt sich mit der Function.call oder der Function.apply-Funktion kompensieren, wie in diesen Code-Schnippseln für Event-Handler.
Für die Erstellung von Objekten (außer reinen Datenspeichern, die mit {} einfach erstellt werden können) verwende ich folgende Grundstruktur:
function Square(id) { // constructor
this.id=id; // Eigenschaften initialisieren
}
(function(){
var p=Square.prototype; // shortcut zum Prototype
p.setId=function(id) { // einfacher Setter
this.id=id;
return this; // macht Setter chainable
};
var privat; // kann nur von den Objektmethoden gesehen werden
function privatauch() {} // dito
})();
var s=new Square (3);
Allerdings bin ich mir nicht sicher, ob das wirklich besser ist, als alles in Konstruktoren zu packen.
Der Code des Onlinegames ist vielleicht nicht ganz so interessant zu lesen, wie es war ihn zu erstellen, aber ich denke, hinein schauen lohnt sich. Ich bin natürlich immer interessiert an weiteren Javascript-Techniken und Tipps zur Code-Gestaltung.


