<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Interaktionsdesigner.de</title>
	<atom:link href="http://www.interaktionsdesigner.de/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.interaktionsdesigner.de</link>
	<description>Der Blog von Paul Lunow über gute und effektive Webentwicklung</description>
	<lastBuildDate>Sun, 18 Mar 2012 08:48:57 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>Facebook Vorschaubilder und TYPO3</title>
		<link>http://www.interaktionsdesigner.de/2012/02/07/facebook-vorschaubilder-und-typo3/</link>
		<comments>http://www.interaktionsdesigner.de/2012/02/07/facebook-vorschaubilder-und-typo3/#comments</comments>
		<pubDate>Tue, 07 Feb 2012 17:24:29 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[TYPO3]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=834</guid>
		<description><![CDATA[Wenn man bei Facebook eine Seite teilt, dann sucht Facebook nach einem passenden Thumbnail. Der geneigte Entwickler gibt dem Spider einen Hinweis über das &#60;link rel="image_src"&#62; Tag. Soweit so einfach. Das kann man natürlich im Template verankern und das Logo hinterlegen, aber was passiert wenn tt_news Beiträge geteilt werden? Die besitzen meistens auch ein Bild [...]]]></description>
			<content:encoded><![CDATA[<p>Wenn man bei Facebook eine Seite teilt, dann sucht Facebook nach einem <strong>passenden Thumbnail</strong>. Der geneigte Entwickler gibt dem Spider einen Hinweis über das <code>&lt;link rel="image_src"&gt;</code> Tag.</p>

<p>Soweit so einfach. Das kann man natürlich im Template verankern und das Logo hinterlegen, aber was passiert wenn <strong>tt_news Beiträge</strong> geteilt werden? Die besitzen meistens auch ein Bild was wesentlich aussagekräftiger ist als das normale Seitenlogo.</p>

<p>Dieser Artikel erklärt wie ein dynamisches <code>link</code>-Tag gebaut wird um in allen Lebenslagen gut zu arbeiten.</p>

<p><span id="more-834"></span></p>

<h2>Standardbild</h2>

<p>Wenn man eine beliebige Seite teilt, dann wird das Logo der Seite angeboten. Nichts leichter als das mit ein paar Zeilen Typoscript. Damit es später einfach ersetzt werden kann, sollte man folgende Struktur übernehmen.</p>

<pre><code>page.headerData.20 = TEXT
page.headerData.20.value = http://meine-domain.de/fileadmin/template/img/logo.png
page.headerData.20.wrap = &lt;img rel="image_src" href="|" /&gt;
</code></pre>

<p>Damit wird das Logo aus dem Fileadmin Ordner hinterlegt, Facebook nimmt es sich automatisch raus. Zur Sicherheit gebe ich die absolute URL an. Variabler bleibt es natürlich wenn man die Baseurl in eine Konstante verlagert und einbindet, aber zum angucken reichts.</p>

<h2>Mit tt_news überschreiben</h2>

<p>Teilt man die Single Ansicht eines tt_news Eintrags soll das ausgewählte Newsbild angezeigt werden. Dazu legt man ein <code>Extensiontemplate</code> auf der entsprechenden Seite an und überschreibt die Eigenschaft in <code>page.headerData.20.value</code> mit dem Wert aus dem Eintrag.</p>

<p>Das Problem ist, der Redakteur kann beliebig viele Bilder mit dem tt_news Eintrag verknüpfen. Für Facebook soll nur das erste angegeben werden. Was muss getan werden?</p>

<ol>
<li>Aktuellen tt_news Eintrag auslesen</li>
<li>Das Feld <code>image</code> abfragen</li>
<li>Inhalte anhand vom Komma <code>,</code> auseinander schneiden</li>
<li>Ersten Wert auswählen</li>
<li>Absolute URL zum Upload erzeugen</li>
</ol>

<p>Und Typoscript wäre nicht Typoscript wenn das nicht "ohne Problem" möglich wäre. Wenn man weiß wie:</p>

<pre><code>page.headerData.20 = RECORDS
page.headerData.20 {
    source = {GPvar:tx_ttnews|tt_news}
    source.insertData = 1
    tables = tt_news
    conf.tt_news &gt;
    conf.tt_news = TEXT
    conf.tt_news.field = image
    conf.tt_news.split {
        token = ,
        cObjNum = 1
        returnKey = 0
    }
    conf.tt_news.wrap = http://meine-domain.de/uploads/pics/|
}
</code></pre>

<p>Über das Element <code>RECORDS</code> wird eine Datenbankabfrage gestartet. Als Quelle wird die übergebene News ID benutzt. Anschließend wird mit Hilfe vom <code>split</code> Befehl das Ergebnis auseinander geschnitten und das erste Ergebnis zurück gegeben (<code>returnKey</code>).</p>

<h2>Fazit</h2>

<p>Wenn man weiß wie, ist Typoscript eine sehr mächtige und umfassende Sprache um alle möglichen und unmöglichen Aufgaben zu lösen.</p>

<p>Nach vielen Stunden der Übung kommt man auch irgendwann dahinter. Nur nicht aufgeben!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2012/02/07/facebook-vorschaubilder-und-typo3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Schönes Javascript mit Callbacks</title>
		<link>http://www.interaktionsdesigner.de/2011/12/07/schones-javascript-mit-callbacks/</link>
		<comments>http://www.interaktionsdesigner.de/2011/12/07/schones-javascript-mit-callbacks/#comments</comments>
		<pubDate>Wed, 07 Dec 2011 14:26:29 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=826</guid>
		<description><![CDATA[Callbacks sind jedem jQuery Anweder bekannt. Von bis zu bindet der Webentwickler jede Menge Logik an festgelegte Events. Meiner Meinung nach eine angenehme Art zu programmieren und gut nachvollziehbar, da der Code gut lesbar bleibt, sofern man nicht übertreibt. Wenn man selbst Applikationen programmiert die auf Javascript basieren und später noch diverse Erweiterungen ermöglichen sollen, [...]]]></description>
			<content:encoded><![CDATA[<p>Callbacks sind jedem jQuery Anweder bekannt. Von <code>onClick</code> bis zu <code>onResize</code> bindet der Webentwickler jede Menge Logik an festgelegte Events. Meiner Meinung nach eine angenehme Art zu programmieren und gut nachvollziehbar, da der Code gut lesbar bleibt, sofern man nicht übertreibt.</p>

<p>Wenn man selbst Applikationen programmiert die auf Javascript basieren und später noch diverse Erweiterungen ermöglichen sollen, dann macht es durchaus Sinn eigene Callbacks anzubieten. Sei es in einer jQuery Extension oder einer eigenen Applikation.</p>

<p><span id="more-826"></span></p>

<h2>Die Anforderung</h2>

<p>Zur Erfüllung meiner aktuellen Anforderung habe ich eine Javascript Klasse erstellt die mit dem Operator <code>new</code> erstellt werden kann:</p>

<pre>var myObject = new FunkyObject();</pre>

<p>Perfekt für die erste Anforderung, aber sobald weitere Entwickler involviert werden oder man Teile der Applikation sogar als OpenSource Software veröffentlicht, wäre es ja schön wenn nicht jeder im eigenen Code rum macht sondern ordentlich in seinem Script bleibt:</p>

<pre>var myObject = new FunkyObject({
&nbsp;&nbsp;onLoad: function() {
&nbsp;&nbsp;&nbsp;&nbsp;//do crazy custom things
&nbsp;&nbsp;}
});</pre>

<p>Sieht ordentlich aus und ist ohne Kommentare selbsterklärend: Beim laden werden verrückte Sachen getan. Aber was tut das FunkyObject um die Callbacks aufzurufen?</p>

<h2>Eine Javascript Klasse</h2>

<p>Genau genommen ist eine Javascript Klasse nichts weiter als eine Funktion die sich selbst zurück gibt und über den <code>new</code> Operator erstellt wird. Meine Grundlage sieht so aus:</p>

<pre>var FunkyObject = function(args) {
&nbsp;&nbsp;var defaults = {};
&nbsp;&nbsp;this.args = $.extend(defaults, args);
&nbsp;&nbsp;this.goCrazy();
&nbsp;&nbsp;return this;
};</pre>

<p>Dieser Code setzt jQuery voraus, das die Funktion <code>$.extend</code> mitbringt. Damit wird das übergebene <code>args</code> Objekt durch die in <code>defaults</code> angegebenen Werte aufgefüllt, sofern sie nicht vorhanden sind. Man kann also für das <code>onClick</code> Event ein Standardverhalten hinterlegen:</p>

<pre>var FunkyObject = function(args) {
&nbsp;&nbsp;var defaults = {
&nbsp;&nbsp;onLoad: function() {
&nbsp;&nbsp;&nbsp;&nbsp;//default behavior
&nbsp;&nbsp;};
&nbsp;&nbsp;this.args = $.extend(defaults, args);
&nbsp;&nbsp;this.goCrazy();
&nbsp;&nbsp;return this;
};</pre>

<p>Die Funktion <code>goCrazy()</code> wird ausgeführt sobald die Klasse initialisiert wird. Um dem nächsten Entwickler die Möglichkeit zu geben auch diese Funktion zu überschreiben, werden alle Grundlagen in der <code>prototype</code> Eigenschaft der Klasse definiert:</p>

<pre>var FunkyObject = function(args) { /* ... */ };
FunkyObject.prototype.goCrazy = function() {
&nbsp;&nbsp;// do the init stuff
};</pre>

<p>Mit diesem Konstrukt könnte ein Entwickler im eigenen Script jene Klasse überschreiben ohne in den eigentlichen Quelltext eingreifen zu müssen.</p>

<pre>myObject.goCrazy = function() {
&nbsp;&nbsp;// custom constructor
}</pre>

<p>Das als kleine Anmerkung am Rande, das erklärte Ziel ist der komfortable Aufruf des <code>onLoad</code> Events. Natürlich könnte man über <code>this.args.onClick()</code> einfach die entsprechende Funktion aufrufen, aber sieht das schön aus? Ist das variabel?</p>

<p>Die Antwort lautet nein.</p>

<h2>Schön und variabel</h2>

<p>Viel cooler ist eine total schöne und variable <code>trigger()</code> Funktion zu schreiben, die in den Parametern nach einem Callback sucht und diesen ggf. ausführt.</p>

<pre>FunkyObject.prototype.trigger = function(action) {
&nbsp;&nbsp;var callback = 'on'+this.ucfirst(action);
&nbsp;&nbsp;if(typeof this.args[callback] == 'function') {
&nbsp;&nbsp;&nbsp;&nbsp;this.argscallback;
&nbsp;&nbsp;};
}</pre>

<p>In der <code>goCrazy</code> Funktion sieht der Aufruf dann so aus:</p>

<pre>var FunkyObject = function(args) { /* ... */ };
FunkyObject.prototype.goCrazy = function() {
&nbsp;&nbsp;this.trigger('load');
};</pre>

<p>Die <code>trigger</code> Funktion baut sich den Eventnamen aus einem <code>on</code> und dem Parameter <code>action</code> zusammen und prüft anschließend ob eine Funktion mit diesem Namen vorhanden ist. Ist dies der Fall wird sie ausgeführt.</p>

<p>Leider gibt es keine Javascript Funktion mit dem Namen <code>ucfirst</code>, aber über die Prototype Eigenschaft kann man das String Objekt entsprechend aufrüsten:</p>

<pre>String.prototype.ucfirst = function() {
&nbsp;&nbsp;return this.substr(0,1).toUpperCase() + this.substr(1,this.length);
};</pre>

<p>Mit diesen zwei Funktionen baut man sich sehr schnell eine Grundlage um variable Scripte zu schreiben die komplett erweitert werden können.</p>

<h2>Parameter für den Callback</h2>

<p>Oft muss der Callback über einen gewissen Zustand informiert werden. Für das benutzte Beispiel könnte es die Information sein ob das Laden erfolgreich war. Bei der Definition des Callbacks muss ein Parameter akzeptiert werden:</p>

<pre>var myObject = new FunkyObject({
&nbsp;&nbsp;onClick: function(success) {
&nbsp;&nbsp;&nbsp;&nbsp;alert(success ? 'hat geklappt!' : 'fehler');
&nbsp;&nbsp;}
});</pre>

<p>Die <code>goCrazy</code> Funktion muss den Status an die <code>trigger</code> Funktion weitergeben:</p>

<pre>FunkyObject.prototype.goCrazy = function() {
&nbsp;&nbsp;success = true;
&nbsp;&nbsp;this.trigger('load', success);
};</pre>

<p>Wir gehen mal von einem grundlegenden Erfolg aus. Das wird es auch sofern die <code>trigger</code> Funktion beigebracht bekommt was sie mit zusätzlichen Parametern anfangen soll:</p>

<pre>FunkyObject.prototype.trigger = function(action) {
&nbsp;&nbsp;var callback = 'on'+this.ucfirst(action);
&nbsp;&nbsp;if(typeof this.args[callback] == 'function') {
&nbsp;&nbsp;&nbsp;&nbsp;this.argscallback;
&nbsp;&nbsp;};
}</pre>

<p>Viele Änderungen sind es nicht. In der vordefinierten Variable <code>arguments</code> sind sämtliche Parameter vom Aufruf der Funktion gespeichert. Die Array Funktion <code>shift</code> entfernt das erste Element aus dem Array und gibt den Rest zurück. So wird nicht der Callbackname sinnloser Weise an den Callback gegeben sondern alle andere Parameter. So kann man auch mehr als ein Wert an den Callback schicken:</p>

<pre>FunkyObject.prototype.goCrazy = function() {
&nbsp;&nbsp;success = true;
&nbsp;&nbsp;this.trigger('load', success, 'ready', {hello: 'world'});
};</pre>

<h2>Fazit</h2>

<p>Ich mag Callbacks. Wenn man ein gutes Grundgerüst hat kann man auf alle Events individuell reagieren. Sollte es ein Callback nicht geben den man wirklich dringend und sofort benötigt kann man mit dem Überschreiben der <code>prototype</code> Funktion kurzfristig neue Callbacks hinzufügen und später in die Core Anwendung übernehmen.</p>

<p>Wichtig ist aber darauf zu achten keine unendlichen Scripte in den Callbacks unterzubringen. Spätestens nach 20 Zeilen sollte man sich überlegen den Code in einzelne Häppchen aufzuteilen.</p>

<p>Und in eigener Sache noch die Warnung vor gedankenlosem Copy and Paste: Durch Unterschrift auf dem NDA musste ich alle Funktionen umbenennen. Also nachdenken und gute Funktionsnamen benutzen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2011/12/07/schones-javascript-mit-callbacks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Die wichtigsten OS X Programme für Entwickler</title>
		<link>http://www.interaktionsdesigner.de/2011/11/28/die-wichtigsten-os-x-programme-fur-entwickler/</link>
		<comments>http://www.interaktionsdesigner.de/2011/11/28/die-wichtigsten-os-x-programme-fur-entwickler/#comments</comments>
		<pubDate>Mon, 28 Nov 2011 17:21:41 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Allgemein]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=818</guid>
		<description><![CDATA[Ab und zu kommt man in die schöne Situation sich an einem neuen Rechner wieder zu finden. Ein sauberes, unverbogenes OS X begrüßt einen mit Standardeinstellungen. Im Arbeitsalltag stolpert man dann ständig über Programme die man doch noch zur Grundausrüstung braucht, die sich schon so in den Arbeitsalltag integriert haben, das man ohne sie nicht [...]]]></description>
			<content:encoded><![CDATA[<p>Ab und zu kommt man in die schöne Situation sich an einem neuen Rechner wieder zu finden. Ein sauberes, unverbogenes OS X begrüßt einen mit Standardeinstellungen. Im Arbeitsalltag stolpert man dann ständig über Programme die man doch noch zur Grundausrüstung braucht, die sich schon so in den Arbeitsalltag integriert haben, das man ohne sie nicht mehr auskommt.</p>

<p>Um dem geneigten Leser bzw. mir selbst beim nächsten Computer die Arbeit zu erleichtern präsentiere ich hier meine Liste mit unverzichtbaren Programmen für den Webentwickler unter Mac OS X. Ergänzungen sind herzlich willkommen.</p>

<p><span id="more-818"></span></p>

<h2>Google Chrome</h2>

<p>Durch die Adresszeile in der man suchen kann und den mittlerweile wirklich großartigen Entwicklertools ein unverzichtbares Werkzeug für den täglichen Gebrauch.</p>

<p><a href="http://www.google.com/chrome" target="_blank">http://www.google.com/chrome</a></p>

<h2>Adblock Plus für Google Chrome</h2>

<p>Ohne Werbeblocker ist das Internet so voll und unübersichtlich, das hält man nicht lange aus. Allerdings sollte man nicht vergessen den Werbeblocker zu deaktivieren wenn man für einen Kunden die Werbeintegration testet.</p>

<p><a href="https://chrome.google.com/webstore/detail/cfhdojbkjhnklbpkdaibdccddilifddb" target="_blank">https://chrome.google.com/webstore/detail/cfhdojbkjhnklbpkdaibdccddilifddb</a></p>

<h2>ClipMenu</h2>

<p>Verlauf für die Zwischenablage. Ohne ClipMenu kann man eigentlich nicht arbeiten. Einfach mit CMD + Umschalt + V ein Kontextmenü aufrufen in dem die letzten 20 Inhalte der Zwischenablage angezeigt werden. Sofort installieren!</p>

<p><a href="http://www.clipmenu.com/" target="_blank">http://www.clipmenu.com/</a></p>

<h2>Quicksilver</h2>

<p>Programme sofort öffnen und viele weitere Funktionen mehr. Nach dem Quicksilver installiert ist, kann das Dock einpacken und zeigt nur noch die offenen Programme an. Sehr interessant ist auch die Plugin Seite auf der die Integration für viele weitere Programme ermöglicht wird.</p>

<p><a href="http://qsapp.com/" target="_blank">http://qsapp.com/</a></p>

<h2>Dropbox</h2>

<p>Mittlerweile unverzichtbar. Viele Programme unterstützen das Speichern ihrer Einstellungen in einer Datei, wenn man den Speicherort in den Dropbox Ordner legt erhält man eine astreine Synchronisierung über mehrere Rechner hinweg.</p>

<p><a href="http://www.dropbox.com" target="_blank">http://www.dropbox.com</a></p>

<h2>MAMP</h2>

<p>Mac, Apache, MySQL und PHP. Der klassische, komfortable Unterbau um schnell und einfach Webseiten zu erstellen.</p>

<p><a href="http://www.mamp.info/de/index.html" target="_blank">http://www.mamp.info/de/index.html</a></p>

<h2>Coda</h2>

<p>Ein guter Editor, FTP Client und Browser der die Webentwicklung enorm erleichtert. Ganz zufrieden bin ich nicht, aber es ist ein solider Editor und Version 2.0 wird bald kommen.</p>

<p><a href="http://panic.com/coda/" target="_blank">http://panic.com/coda/</a></p>

<h2>Transmit</h2>

<p>Obwohl Coda einen FTP Client eingebaut hat, brauche ich für einige Anwendungsfälle ein eigenständiges FTP Programm. Transmit kostet zwar Geld, ist es aber aufjedenfall wert!</p>

<p><a href="http://panic.com/transmit/" target="_blank">http://panic.com/transmit/</a></p>

<h2>Git</h2>

<p>Mit diesem praktischen Installationsprogramm muss man sich keine großen Gedanken machen außer über die Doppelklick Geschwindigkeit.</p>

<p><a href="http://code.google.com/p/git-osx-installer/" target="_blank">http://code.google.com/p/git-osx-installer/</a></p>

<h2>OpenOffice</h2>

<p>Aus irgendeinem Grund gibt es kein wirklich brauchbares Textverarbeitungsprogramm. Gerade im Hinblick auf die Kollegen mit Windows oder Linux führt leider kein Weg an OpenOffice vorbei.</p>

<p><a href="http://download.openoffice.org/" target="_blank">http://download.openoffice.org/</a></p>

<h2>UnRarX</h2>

<p>Schnell, zuverlässig und kostenlos Rar Archive entpacken</p>

<p><a href="http://www.unrarx.com/" target="_blank">http://www.unrarx.com/</a></p>

<h2>VLC</h2>

<p>Der Videoplayer der so gut wie jedes Videoformat abspielt. Unverzichtbar.</p>

<p><a href="http://www.videolan.org/" target="_blank">http://www.videolan.org/</a></p>

<h2>Sykpe</h2>

<p>Ohne Skype keine Kommunikation auf dem Rechner. Verdammt einsam ohne.</p>

<p><a href="http://www.skype.com/" target="_blank">http://www.skype.com/</a></p>

<h2>HexPicker</h2>

<p>Erweitert den OSX Farben Dialog um einen weiteren Reiter der den Hexcode für die gewählte Farbe ausgeben kann.
Interessante Alternative ist der Picker von Panic: http://www.panic.com/~wade/picker/</p>

<p><a href="http://wafflesoftware.net/hexpicker/" target="_blank">http://wafflesoftware.net/hexpicker/</a></p>

<h2>SpotColor</h2>

<p>Das war ein grandioses Programm das den OSX Farben Dialog als separates Programm zur Verfügung gestellt hat. Trauriger Weise in ein neues, kostenpflichtes Programm transformiert. Aber der Code befindet sich auf Github für den interessierten Entwickler (https://github.com/0xced/SpotColor).</p>

<p><a href="http://zachwaugh.com/spotcolor/" target="_blank">http://zachwaugh.com/spotcolor/</a></p>

<h2>Archiver</h2>

<p>Nettes, gut aussehendes Programm um alle möglichen und unmöglichen Programme zu Packen und entpacken. Kostet eine Kleinigkeit, gab es mal für einen Tweed umsonst.</p>

<p><a href="http://archiverapp.com/" target="_blank">http://archiverapp.com/</a></p>

<h2>CoRD</h2>

<p>Nettes Programm um auf die per RDP verbundenen Rechner zuzugreifen. In unserem Fall sind das die Internet Explorer Testmaschinen die fernab von Sonnenlicht im Serverraum versteckt sind.</p>

<p><a href="http://cord.sourceforge.net/" target="_blank">http://cord.sourceforge.net/</a></p>

<h2>Notational Velocity</h2>

<p>Grandios schnelles und einfach zu bedienendes Snippets Programm. Darauf ausgelegt ausschließlich über die Tastatur bedient zu werden. Im Zusammenspiel mit Quicksilver und Dropbox ein starkes Tool auf allen zur Verfügung stehenden Rechnern.</p>

<p><a href="http://notational.net/" target="_blank">http://notational.net/</a></p>

<h2>Skitch</h2>

<p>Das perfekte Screenshot Tool um die entschiedenen Teile einer Applikation für die Kunden oder die Familie hervor zu heben.</p>

<p><a href="http://skitch.com/" target="_blank">http://skitch.com/</a></p>

<h2>Adressbuch und Kalender</h2>

<p>Netter Weise schon von OSX Lion mitgeliefert, aber was die sich bei dem Design gedacht haben bleibt verborgen. Zum Glück gibt es einen komfortablen Installier um sich ein etwas ansehnlicheres Aluminium Design zurück zu holen: <a href="http://macuser-dresden.de/archives/2011/07/adressbuch-und-ical-vom-leder-zuruck-zu-aluminium-fur-mac-os-x-lyon/" target="_blank">http://macuser-dresden.de/archives/2011/07/adressbuch-und-ical-vom-leder-zuruck-zu-aluminium-fur-mac-os-x-lyon/</a></p>

<h2>Fazit</h2>

<p>Es gibt so viele schöne Programme für OS X, alle hier aufgeführten funktionieren auch ohne weiteres auf OS X Lion.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2011/11/28/die-wichtigsten-os-x-programme-fur-entwickler/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SEO und TYPO3</title>
		<link>http://www.interaktionsdesigner.de/2011/10/10/seo-und-typo3/</link>
		<comments>http://www.interaktionsdesigner.de/2011/10/10/seo-und-typo3/#comments</comments>
		<pubDate>Mon, 10 Oct 2011 12:53:03 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[TYPO3]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=805</guid>
		<description><![CDATA[Da wir ein paar sehr schöne TYPO3 Seiten realisiert haben die jetzt im Internet auch gut gefunden werden sollen, geht es in dieser Ausgabe um das Optimieren einer TYPO3 Internetseite mit möglichst wenig Aufwand und schnellen Erfolgen. Vorweg bleibt zu sagen das neben der On-Site-Optimierung die Off-Site-Optimierung eine bedeutende Rolle spielt. Aber die ist wie [...]]]></description>
			<content:encoded><![CDATA[<p>Da wir ein paar sehr schöne TYPO3 Seiten realisiert haben die jetzt im Internet auch gut gefunden werden sollen, geht es in dieser Ausgabe um das <strong>Optimieren einer TYPO3 Internetseite</strong> mit möglichst wenig Aufwand und schnellen Erfolgen.</p>

<p>Vorweg bleibt zu sagen das neben der <strong>On-Site-Optimierung</strong> die Off-Site-Optimierung eine bedeutende Rolle spielt. Aber die ist wie Rudern gegen den Strom. Wenn man nachlässt wird man zurück getrieben. Irgendwer hat das gesagt, ich weiß leider nicht mehr wer, aber es stimmt.</p>

<p>Für dauerhafte, erfolgreiche Suchmaschinenoptimierung muss man also wohl oder übel in die Taschen greifen und <a title="Ich würde sogar sagen die beste Agentur" href="http://www.apeunit.com" target="_blank">eine gute Agentur</a> damit beauftragen. Für das kleine Budget gibt es aber auch schon einige Tricks.
<span id="more-805"></span></p>

<h2>RealURL oder CoolURI</h2>

<p>Sprechende Urls sind natürlich wahnsinnig wichtig und die Grundlage für jede Optimierung. Anleitungen und Tutorials bieten die Extension Manuals oder Google mehr als genug.</p>

<p>Da mich RealURL in der Vergangenheit schon öfters zur Weißglut gebracht hat bevorzuge ich für überschaubare Internetauftritte im Moment <a href="http://typo3.org/extensions/repository/view/cooluri/current/" target="_blank">CoolURI</a>.</p>

<p>CoolURI hat seine komplette Konfiguration in einer XML Datei. Die Grundlage dafür befindet sich in <code>typo3conf/ext/cooluri/test/CoolUriConf.xml</code> und muss von dort in den <code>typo3conf/</code> Ordner geschoben werden. Die Konfiguration ist recht überschaubar, mit Kommentaren versehen und ordentlich voreingestellt.</p>

<p>Auf Root Ebene muss die von TYPO3 mitgelieferte <code>_.htacces</code> Datei in <code>.htaccess</code> umbenannt werden. Anschließend im Typoscript die Extension aktivieren:</p>

<pre>config.baseURL = http://www.deineseite.de/
config.tx_cooluri_enable = 1
config.redirectOldLinksToNew = 1</pre>

<p>Anschließend Cache leeren und das Frontend neuladen - fertig. Wunderschöne Urls.</p>

<h2>Google Sitemap</h2>

<p>Extension <a href="http://typo3.org/extensions/repository/view/mc_googlesitemap/current/" target="_blank">mc_googlesitemap</a> installieren. Nach dem Import und dem Update der Datenbank muss eine neue Seite angelegt werden und darauf ein Inhaltselement "Menü / Sitemap".</p>

<p>Ist dieses ausgewählt wählt man den Typ <code>Google Sitemap für Seiten</code> und die Root Seite als Ausgangspunkt. So einfach! Über Google Webmaster Tools kann man die Sitemap überprüfen lassen und direkt in das hungrige Spidermaul vom Suchmaschinenriesen werfen.</p>

<h2>Google Webmaster Tools</h2>

<p>Um sich vom allmächtigen Internetriesen helfen zu lassen, sollte man sich bei den Google Webmaster Tools anmelden und die eigene Seite hinzufügen. Hier findet man nützliche Informationen über Fehler, Suchanfragen und Spiderresultate.
<a href="https://www.google.com/webmasters/tools/" target="_blank"> https://www.google.com/webmasters/tools/</a></p>

<h2>Metatags</h2>

<p>Diverse Quellen behaupten zwar, dass Google die Daten nicht mehr zum Indexieren benutzt, trotzdem erscheinen sie als Beschreibungstext in den Suchergebnissen oder wenn die Seite bei Facebook geteilt wird. Um dem Redakteur ein bearbeiten zu ermöglichen stehen schon Felder in den Seiteneigenschaften bereit. Man muss diese nur mit ein paar Zeilen Typoscript in die HTML Ausgabe bringen:</p>

<pre>page.meta.keywords.field = keywords
page.meta.description.field = description</pre>

<h2>Seitentitel</h2>

<p>Je weiter vorne ein Begriff steht umso höher wird die Wichtigkeit von jenem eingeschätzt. In TYPO3 gibt es zwei Wege das Standardverhalten im Seitentitel "Projektname: Seitenname" zu ändern.</p>

<p>Entweder über eine Typoscript Eigenschaft:</p>

<pre>config.pageTitleFirst = 1</pre>

<p>Oder in dem man die Standardausgabe unterdrückt und das Title-Tag selbst generiert:</p>

<pre>config.noPageTitle = 2
page.headerData.10 = TEXT
page.headerData.10.field = subtitle // title
page.headerData.10.wrap = &lt;title&gt;| &amp;nbsp; - deinedomain.com&lt;/title&gt;</pre>

<p>Um den Seitentitel mit Keywords zu füllen und das Menü trotzdem nicht explodieren zu lassen findet man im Backend die Felder "Page Title" und "Alternative Navigation Title". Ersteres wird im Title Tag ausgegeben, letzteres im Menü benutzt.</p>

<p>RealURL bietet darüber hinaus noch das Feld "Speaking URL path Segment" an über den die URL beeinflusst wurden kann.</p>

<h2>Fazit</h2>

<p><strong>Suchmaschinenoptimierung</strong> ist ein langes und aufwendiges Thema. <a title="Die Internetagentur aus Berlin" href="http://www.apeunit.com" target="_self">Wir</a> verkaufen immer "suchmaschinenfreundliche" Webseiten. Neben der Umsetzung der oben genannten Tipps ist eine saubere HTML Struktur und eine bestätigte Fehlerfreiheit durch den W3C Validator unverzichtbar.</p>

<p>Neben dem Sammeln von Links von Außen, welche Maßnahmen ergreift ihr um eure TYPO3 Projekte weiter nach vorne zu bringen?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2011/10/10/seo-und-typo3/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>jQuery Deferred verstehen und bessere Scripte schreiben</title>
		<link>http://www.interaktionsdesigner.de/2011/03/23/jquery-deferred-verstehen-und-bessere-scripte-schreiben/</link>
		<comments>http://www.interaktionsdesigner.de/2011/03/23/jquery-deferred-verstehen-und-bessere-scripte-schreiben/#comments</comments>
		<pubDate>Wed, 23 Mar 2011 10:01:44 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=795</guid>
		<description><![CDATA[jQuery 1.5 ist schon eine Weile draußen und hat ein neues tolles Konzept mitgebracht das ich unbedingt vorstellen möchte, denn damit schreibt man bessere Scripte, die übersichtlicher sind und zuverlässiger funktionieren. Es heißt: Deferred und ist eigentlich sehr leicht zu verstehen. Mit jQuery.Deferred lassen sich Objekte erzeugen, die beim erreichen eins Zustandes bescheid geben, damit [...]]]></description>
			<content:encoded><![CDATA[<p><strong>jQuery 1.5</strong> ist schon eine Weile draußen und hat ein neues tolles Konzept mitgebracht das ich unbedingt vorstellen möchte, denn damit schreibt man bessere Scripte, die übersichtlicher sind und zuverlässiger funktionieren. Es heißt: <strong>Deferred</strong> und ist eigentlich sehr leicht zu verstehen.</p>

<p>Mit <strong>jQuery.Deferred</strong> lassen sich Objekte erzeugen, die beim erreichen eins Zustandes bescheid geben, damit andere Objekte darauf reagieren können. Klingt verworren ist aber ganz einfach, zum Beispiel sollen die Bilder angezeigt werden wenn sie fertig geladen sind.</p>

<p><span id="more-795"></span></p>

<h2>Ohne $.Deferred</h2>

<p>Vor jQuery 1.5 musste man sich mit Callbacks oder <code>window.setTimeout()</code> helfen um auf Ereignisse zu reagieren.</p>

<pre>$('#elem').fadeIn(function() {
&nbsp;&nbsp;// do something when #elem is visible
});</pre>

<p>Bei einem Element ist das leicht, aber wenn es sich um <strong>mehrere Elemente</strong> handelt, oder man nicht genau sagen kann wann ein Element einen Status erreicht hat, dann wirds kritisch.</p>

<h2>Mit $.Deferred</h2>

<p>Die großartigen Funktionen heißen <code>$.when()</code> und <code>$.then()</code>. In meinem letzten Projekt musste ich warten bis mehrere Bilder geladen wurden. So sieht der Aufruf aus:</p>

<pre>$.when(loadImg('#img1')).then(function() {
&nbsp;&nbsp;//do stuff, the image is loaded
});</pre>

<p>Zugegeben, das kann auch leichter haben mit <code>$('#img1').load(function() { /* action */ })</code>, richtig schön wird es auch bei mehreren Bildern:</p>

<pre>$.when(
&nbsp;&nbsp;loadImg('#img1'),
&nbsp;&nbsp;loadImg('#img2'),
&nbsp;&nbsp;loadImg('#img3'))
.then(function() {
&nbsp;&nbsp;//do stuff, all images are loaded
});</pre>

<p>Die Funktion <code>$.then()</code> wird erst ausgeführt wenn alle Funktionen in <code>$.when()</code> ihr okay gegeben haben. Genial oder?</p>

<p>Die Funktion <code>loadImg()</code> muss natürlich entsprechend vorbereitet werden, damit sie okay sagen kann.</p>

<pre>function loadImg(selector) {
&nbsp;&nbsp;var dfd = $.Deferred();
&nbsp;&nbsp;$(selector).load(function() { dfd.resolve(); });
&nbsp;&nbsp;return dfd.promise();
}</pre>

<p>In der Variable <code>dfd</code> wird ein neues <strong>Deferred Objekt</strong> erzeugt. Die Rückgabe der Funktion muss von diesem Objekt die Funktion <code>promise()</code> ausgeben.</p>

<p>Und wenn die Funktion ihr erklärtes Ziel erreicht hat, wird die Funktion <code>resolve()</code> aufgerufen. Damit ist der Funktion <code>$.when()</code> klar das sie ggf. weitermachen kann.</p>

<h2>Fazit</h2>

<p>jQuery Magic vom feinsten! Das war ein sehr kleiner Einstieg in dieses großartige Konzept, <strong>Deferred</strong> kann noch einiges mehr und die <a title="Deferred in jQuery" href="http://api.jquery.com/category/deferred-object/" target="_blank">offizielle jQuery Dokumentation</a> verrät was.</p>

<p>Ich wünsche viel Spaß beim programmieren und coole neue Scripte.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2011/03/23/jquery-deferred-verstehen-und-bessere-scripte-schreiben/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>CakePHP Expandable Behavior</title>
		<link>http://www.interaktionsdesigner.de/2011/02/11/cakephp-expandable-behavior/</link>
		<comments>http://www.interaktionsdesigner.de/2011/02/11/cakephp-expandable-behavior/#comments</comments>
		<pubDate>Fri, 11 Feb 2011 14:24:47 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[CakePHP]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=786</guid>
		<description><![CDATA[Darf ich vorstellen: mein CakePHP Expandable Behavior. Ein einfaches, kleines Script welches das hinzufügen von neuen Spalten in einem beliebigen CakePHP Model erlaubt, ohne die Datenbank zu verändern. Neue Spalten werden in einer Tabelle und die Inhalte in einer anderen Tabelle gespeichert. Beim Auslesen werden die Ergebnisse so zusammen gefasst, dass es für den normalen [...]]]></description>
			<content:encoded><![CDATA[<p>Darf ich vorstellen: mein <strong>CakePHP Expandable Behavior</strong>. Ein einfaches, kleines Script welches das hinzufügen von neuen Spalten in einem beliebigen CakePHP Model erlaubt, <strong>ohne die Datenbank zu verändern</strong>. Neue Spalten werden in einer Tabelle und die Inhalte in einer anderen Tabelle gespeichert.</p>

<p>Beim Auslesen werden die Ergebnisse so zusammen gefasst, dass es für den normalen Programmierer kein Unterschied gibt. Die neuste Version findet man auf <a title="CakePHP Expandable Behavior" href="https://github.com/apeunit/Expandable" target="_blank">GitHub</a>, die Erklärung zur Installation und Nutzung in diesem Eintrag.</p>

<p><span id="more-786"></span></p>

<h2>Voraussetzungen</h2>

<p>Das Expandable Behavior erwartet zwei Tabellen <code>Keys</code> und <code>Values</code>:</p>

<pre>CREATE TABLE IF NOT EXISTS 'keys' (
&nbsp;&nbsp;'id' int(3) unsigned NOT NULL AUTO_INCREMENT,
&nbsp;&nbsp;'model' varchar(25) COLLATE utf8_bin NOT NULL,
&nbsp;&nbsp;'key' varchar(50) COLLATE utf8_bin NOT NULL,
&nbsp;&nbsp;PRIMARY KEY ('id')
) ENGINE=InnoDB&nbsp;&nbsp;DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE IF NOT EXISTS 'values' (
&nbsp;&nbsp;'id' int(6) unsigned NOT NULL AUTO_INCREMENT,
&nbsp;&nbsp;'key_id' int(3) NOT NULL,
&nbsp;&nbsp;'model_id' int(6) NOT NULL,
&nbsp;&nbsp;'value' text COLLATE utf8_bin NOT NULL,
&nbsp;&nbsp;PRIMARY KEY (id)
) ENGINE=InnoDB&nbsp;&nbsp;DEFAULT CHARSET=utf8 COLLATE=utf8_bin;</pre>

<p>Außerdem sollte man das <strong>Containable Behavior</strong> für das Model aktiviert haben. Ansonsten fehlt nur noch die Datei aus dem <a title="CakePHP Expandable Behavior" href="https://github.com/apeunit/Expandable" target="_blank">Repository auf GitHub</a>.</p>

<h2>Installation</h2>

<p>Ein schönes Beispiel ist das Model <code>Document</code>. In meinem Projekt gibt es die Möglichkeit beliebige Dateien hochzuladen, jede Datei hat dabei andere Eigenschaften die dazu mit gespeichert werden sollen. Jetzt könnte man alle Spalten anlegen und nur die benötigten ausfüllen, was aber zu einer äußerst unangenehmen Tabelle führt. Da doch lieber das Expandable Behavior. Die Tabelle <code>documents</code> besitzt folgende Spalten:</p>

<pre>ID
created
modified
user_id
title
file
extension
is_hidden</pre>

<p>Für ein OpenOffice Dokument soll der Benutzer jetzt die Anzahl Seiten eintragen können. Das macht für ein Video natürlich keinen Sinn. Jetzt kommt das Expandable Behavior ins Spiel.</p>

<pre>class Document extends AppModel {
&nbsp;&nbsp;var $actsAs = array('Containable', 'Expandable');
}</pre>

<p>Fertig!</p>

<h2>Speichern</h2>

<p>Im View kann man jetzt ein Formular mit beliebigen Feldern anlegen, zum Beispiel für ein neues OpenOffice Dokument:</p>

<pre>&lt;?php
echo $this-&gt;Form-&gt;create('Document');
echo $this-&gt;Form-&gt;input('title');
echo $this-&gt;Form-&gt;input('file', array('type' =&gt; 'file'));
echo $this-&gt;Form-&gt;input('pages');
echo $this-&gt;Form-&gt;end('Save');
?&gt;</pre>

<p>Das Feld <code>pages</code> wird beim Speichern erkannt, eventuell in der Datenbank <code>keys</code> ein neuer Eintrag erzeugt und in <code>values</code> die Inhalte gespeichert. So einfach.</p>

<p>Neue Felder werden nur angelegt, wenn <code>debug</code> größer als 0 ist.</p>

<h2>Validierung</h2>

<p>Es lassen sich wie gewohnt alle Cake Validierungsregeln auf die dynamischen Felder anwenden.</p>

<pre>class Document extends AppModel {
&nbsp;&nbsp;$validate = array('pages' =&gt; array('rule' =&gt; 'numeric'));
}</pre>

<h2>Auslesen</h2>

<p>Hier muss man auf eine Sache achten. Normalerweise sieht die Abfrage so aus:</p>

<pre>$document = $this-&gt;Document-&gt;find('first', array(
&nbsp;&nbsp;'conditions' =&gt; array('Document.id' =&gt; $document_id),
));</pre>

<p>Da erhält man jetzt für jeden dynamisch angelegten Key einen leeren Eintrag weil die Inhalte nicht automatisch geladen werden. Das muss beim auslesen noch mit angegeben werden:</p>

<pre>$document = $this-&gt;Document-&gt;find('first', array(
&nbsp;&nbsp;'conditions' =&gt; array('Document.id' =&gt; $document_id),
&nbsp;&nbsp;'contain' =&gt; array('Value')
));</pre>

<p>Über das Containable Behavior werden alle zugehörigen Inhalte ausgelesen, das Expandable Behavior kümmert sich um den Rest.</p>

<pre>$this-&gt;Document-&gt;getKeys();</pre>

<p>Die Funktion <code>getKeys()</code> aus dem Behavior liefert ein Array mit allen dynamisch angelegten Schlüsseln. Ganz praktisch um dynamische Formulare aufzubauen.</p>

<h2>ToDo</h2>

<p>Ganz fertig ist die Arbeit noch nicht.</p>

<ul>
    <li>Ich habe im <code>beforeFind()</code> Callback alles versucht, aber ich kriege Cake einfach nicht dazu die Inhalte automatisch mit auszulesen.</li>
    <li>Es wäre natürlich nett die <code>values</code> auch im Paginator nutzen zu können. Das muss noch untersucht werden.</li>
    <li>Die Keys sollten verschiedene Typen ermöglichen, z.B. für Zahlen, Text oder Floats. Im Moment wird einfach alles in einem Feld vom Typ <code>Text</code> gespeichert.</li>
</ul>

<h2>Fazit</h2>

<p>Das Behavior funktioniert bisher super, ist allerdings noch in einer sehr frühen Entwicklungsphase. Wer einen Fehler findet ist herzlich eingeladen einen Patch über <a title="CakePHP Expandable Behavior" href="https://github.com/apeunit/Expandable" target="_blank">GitHub</a> zu schicken.</p>

<p>Bisher macht es großen Spaß neue Felder anzulegen ohne sich über die Datenbank Gedanken zu machen. Mal sehen was daraus noch wird.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2011/02/11/cakephp-expandable-behavior/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mobile Webseiten mit jQuery Mobile und CakePHP</title>
		<link>http://www.interaktionsdesigner.de/2011/01/27/mobile-webseiten-mit-jquery-mobile-und-cakephp/</link>
		<comments>http://www.interaktionsdesigner.de/2011/01/27/mobile-webseiten-mit-jquery-mobile-und-cakephp/#comments</comments>
		<pubDate>Thu, 27 Jan 2011 18:54:07 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[jQuery Mobile]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=768</guid>
		<description><![CDATA[Zwei großartige Frameworks, vereint um die mobile Welt zu verbessern, bereichern und verändern. Mit CakePHP baut man in wenigen Schritten eine mobile Applikation die auf allen Smartphones gut aussieht mit Hilfe von jQuery Mobile. CakePHP vorbereiten Um in allen Teilen der Applikation zu erkennen, ob ein mobiles Endgerät auf die Seite zugreift, definiert man im [...]]]></description>
			<content:encoded><![CDATA[<p>Zwei großartige Frameworks, vereint um die mobile Welt zu verbessern, bereichern und verändern. Mit <strong>CakePHP</strong> baut man in wenigen Schritten eine mobile Applikation die auf allen Smartphones gut aussieht mit Hilfe von <strong>jQuery Mobile</strong>.</p>

<p><span id="more-768"></span></p>

<h2>CakePHP vorbereiten</h2>

<p>Um in allen Teilen der Applikation zu erkennen, ob ein mobiles Endgerät auf die Seite zugreift, definiert man im AppController eine Variable <code>$isMobile</code>.</p>

<pre>class AppController extends Controller {
&nbsp;&nbsp;var $isMobile = false;
}</pre>

<p>In der Funktion <code>beforeFilter()</code> wird mit Hilfe des RequestHandlers das mobile Endgerät erkannt:</p>

<pre>function beforeFilter() {
&nbsp;&nbsp;if($this-&gt;RequestHandler-&gt;isMobile() || isset($this-&gt;params['url']['mobile'])) {
&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;layout = 'mobile';
&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;isMobile = true;
&nbsp;&nbsp;}
&nbsp;&nbsp;$this-&gt;set('is_mobile', $this-&gt;isMobile);
}</pre>

<p>Die Variable <code>isMobile</code> wird auf <code>true</code> gesetzt und das Layout <code>mobile</code> genutzt. Um es in der gewohnten Umgebung zu testen, erlaube ich auch den URL Parameter <code>mobile</code>, mit dem jeder View per <code>?mobile=1</code> im mobilen Layout angezeigt werden kann.</p>

<p>Bei einer richtig guten Applikation ist die Arbeit damit getan und alle Views funktionieren auch in der mobilen Version. Realistischer ist aber das man in der mobilen Version anderen HTML Code braucht und nur einen Teil der Funktionalität zur Verfügung stellt. Das erreicht man über angepasste Views.</p>

<p>In der Funktion <code>beforeRender()</code> kann der View verändert werden. Meine Lieblingsfunktion sieht so aus:</p>

<pre>function beforeRender() {
&nbsp;&nbsp;if($this-&gt;isMobile) {
&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;action = 'mobile/'.$this-&gt;action;
&nbsp;&nbsp;}
}</pre>

<p>Entweder man fügt diese Funktion im <code>AppController</code> ein und leitet für die gesamte Applikation alle Views in den mobile Ordner weiter, oder nur in den betreffenden Controllern.</p>

<p>Nach dem abarbeiten der Funktion im Controller wird der View in den mobile Ordner weiter geleitet. Cake sucht jetzt für den Aufruf von <code>/users/login</code> den View in <code>app/views/users/mobile/login.ctp</code>.</p>

<h2>jQuery Mobile im CakePHP Layout</h2>

<p>Jetzt kommt der schöne Teil! Eine mobile Applikation mit jQuery mobile bauen. Grundlage ist ein HTML5 Grundgerüst:</p>

<pre>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&nbsp;&nbsp;&lt;head&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;title&gt;HTML5 Gerüst&lt;/title&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;meta charset="utf8"&gt;
&nbsp;&nbsp;&lt;/head&gt;
&nbsp;&nbsp;&lt;body&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;h1&gt;Hallo Welt&lt;/h1&gt;
&nbsp;&nbsp;&lt;/body&gt;
&lt;/html&gt;</pre>

<p>Die üblichen Variablen aus dem CakePHP View können natürlich nach belieben eingesetzt werden, ich denke da an <code>$title_for_layout</code> und <code>$content_for_layout</code>. Wirklich entscheidend ist aber jQuery mobile.</p>

<p>Auf der Downloadseite gibt es ein praktisches Copy Paste Snippet um jQuery und jQuery Mobile aus dem CDN einzubinden:</p>

<pre>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&nbsp;&nbsp;&lt;head&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;title&gt;HTML5 Gerüst&lt;/title&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;meta charset="utf8"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a2/jquery.mobile-1.0a2.min.css" /&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;script src="http://code.jquery.com/jquery-1.4.4.min.js"&gt;&lt;/script&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;script src="http://code.jquery.com/mobile/1.0a2/jquery.mobile-1.0a2.min.js"&gt;&lt;/script&gt;
&nbsp;&nbsp;&lt;/head&gt;
&nbsp;&nbsp;&lt;body&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;div data-role="page"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;div data-role="header"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;h1&gt;Hallo Welt!&lt;/h1&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/div&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;div data-role="content"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;p&gt;Meine erste mobile Seite&lt;/p&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/div&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/div&gt;
&nbsp;&nbsp;&lt;/body&gt;
&lt;/html&gt;</pre>

<p>Bei jQuery Mobile läuft sehr viel über das <code>data</code> Attribut eines Elements. Seite, Kopf und Inhalt werden darüber deklariert. In jQuery ließt man diese Eigenschaften übrigens sehr einfach über die <code>data()</code> Funktion aus.</p>

<pre>$('div').data('role'); // returns string
$('div').data(); // returns object</pre>

<h2>Konfiguration</h2>

<p>Es gibt Standardeinstellungen, Callbacks und Events auf die man in Javascript reagieren kann. Allerdings muss man den eigenen Code vor dem Einbinden von jQuery Mobile anlegen! So siehts aus:</p>

<pre>&lt;script src="jquery.min.js"&gt;&lt;/script&gt;
&lt;script&gt;
&nbsp;&nbsp;$(document).bind("mobileinit", function(){
&nbsp;&nbsp;&nbsp;&nbsp;//apply overrides here
&nbsp;&nbsp;});
&lt;/script&gt;
&lt;script src="jquery.mobile.min.js"&gt;&lt;/script&gt;</pre>

<h2>Formulare</h2>

<p>jQuery Mobile erwartet einen Container der das Label und das Inputfeld umschließt. Kein Problem sagt der Cake Entwickler erst, dann bemerkt er aber das der Container das Data Attribut <code>fieldcontainer</code> braucht. Zum Glück auch kein Problem, da man dem FormHelper beim erstellen des Formulars Standardeigenschaften mitgeben kann:</p>

<pre>echo $this-&gt;Form-&gt;create('User', array(
&nbsp;&nbsp;'action' =&gt; 'login',
&nbsp;&nbsp;'inputDefaults' =&gt; array(
&nbsp;&nbsp;&nbsp;&nbsp;'div' =&gt; array('data-role' =&gt; 'fieldcontain')
&nbsp;&nbsp;),
));</pre>

<p>jQuery Mobile kümmert sich jetzt von selbst um die korrekte Darstellung. Bei viel Platz werden Label und Inputelement nebeneinander, bei weniger Platz untereinander dargestellt. Submitbuttons werden automatisch schick dargestellt.</p>

<h2>Fazit</h2>

<p>Es gibt eine Menge Dinge man beim Arbeit mit jQuery Mobile entdecken kann. Es macht großen Spaß und funktioniert gut über die meisten mobilen Endgeräte hinweg. Die Dokumentation von jQuery Mobile ist mit jQuery Mobile erstellt. Dazu ein Trick: Wenn man die Seite gefunden hat, die genau das darstellt was man sucht, dann entfernt man die Raute aus der URL und öffnet anschließend den Quelltext der Seite um zu verstehen wie das Feature aufgebaut ist.</p>

<p>Da alles dynamisch geladen wird, vom Framework angepasst und erweitert wird, wird man im Firebug durch jede Menge Kram abgelenkt. Will man also herausfinden wie durchsuchbare Listen aufgebaut sind, navigiert man auf die entsprechende Seite in der Doku:</p>

<pre>http://jquerymobile.com/demos/1.0a2/#docs/lists/lists-search.html</pre>

<p>Und entfernt die Raute:</p>

<pre>http://jquerymobile.com/demos/1.0a2/docs/lists/lists-search.html</pre>

<p>Und erkennt das es äußerst einfach, genial und zukunftsfähig aufgebaut ist:</p>

<pre>&lt;div data-role="page"&gt;

&nbsp;&nbsp;&lt;div data-role="header"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;h1&gt;Search filter bar&lt;/h1&gt;
&nbsp;&nbsp;&lt;/div&gt;&lt;!-- /header --&gt;

&nbsp;&nbsp;&lt;div data-role="content"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ul data-role="listview" data-filter="true"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Acura&lt;/a&gt;&lt;/li&gt;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Audi&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;BMW&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Cadillac&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Chrysler&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Dodge&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Ferrari&lt;/a&gt;&lt;/li&gt;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Ford&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;GMC&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Honda&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Hyundai&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Infiniti&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Jeep&lt;/a&gt;&lt;/li&gt;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Kia&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Lexus&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Mini&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Nissan&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Porsche&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Subaru&lt;/a&gt;&lt;/li&gt;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Toyota&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Volkswagon&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;li&gt;&lt;a href="index.html"&gt;Volvo&lt;/a&gt;&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ul&gt;
&nbsp;&nbsp;&lt;/div&gt;&lt;!-- /content --&gt;
&lt;/div&gt;&lt;!-- /page --&gt;</pre>

<p>Ist das nicht schön?</p>

<p>Beim schreiben sind mir eine ganze Menge Themen aufgefallen die unbedingt noch behandelt werden müssen: <strong>Links</strong>, <strong>Ajax</strong> und <strong>Maps</strong>.</p>

<p>Wie sind deine Erfahrungen mit jQuery Mobile?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2011/01/27/mobile-webseiten-mit-jquery-mobile-und-cakephp/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Die eine Zeile zum jQuery Tab</title>
		<link>http://www.interaktionsdesigner.de/2011/01/17/jquery-super-cool/</link>
		<comments>http://www.interaktionsdesigner.de/2011/01/17/jquery-super-cool/#comments</comments>
		<pubDate>Mon, 17 Jan 2011 07:30:54 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=760</guid>
		<description><![CDATA[jQuery ist ein großartiges Javascript Framework. Mit einer einzigen Zeile kann man ein komplettes Tab Widget bauen. In meinem aktuellen Projekt kann der Benutzer unter einer großen Auswahl Elementen wählen. Jedes Element gehört in eine Kategorie. Also wäre es doch nett oben eine Kategorie anzuklicken und anschließend nur die Einträge dieser Kategorie zu sehen. Nichts [...]]]></description>
			<content:encoded><![CDATA[<p><strong>jQuery</strong> ist ein großartiges <strong>Javascript Framework</strong>. Mit einer einzigen Zeile kann man ein komplettes <strong>Tab Widget</strong> bauen.</p>

<p>In meinem aktuellen Projekt kann der Benutzer unter einer großen Auswahl Elementen wählen. Jedes Element gehört in eine Kategorie. Also wäre es doch nett oben eine Kategorie anzuklicken und anschließend nur die Einträge dieser Kategorie zu sehen.</p>

<p>Nichts leichter als das! Es gibt natürlich großartige und weniger gute Plugins zu dem Thema, aber es ist <strong>in einer Zeile selbst geschrieben</strong>. Macht Spaß und verdeutlicht die <strong>Verkettung in jQuery</strong>.</p>

<p><span id="more-760"></span></p>

<h2>Das HTML Gerüst</h2>

<p>Damit fängt es immer an. So sieht es leicht gekürzt aus:</p>

<pre>&lt;div class="categories"&gt;
&nbsp;&nbsp;&lt;ul&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;li data-id="1"&gt;Kategorie 1&lt;/li&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;li data-id="2"&gt;Kategorie 2&lt;/li&gt;
&nbsp;&nbsp;&lt;/ul&gt;

&nbsp;&nbsp;&lt;div id="category_1" class="category"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;!-- jede Menge Inhalt --&gt;
&nbsp;&nbsp;&lt;/div&gt;
&nbsp;&nbsp;&lt;div id="category_2" class="category"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;!-- noch  mehr Inhalt in Kategorie 2 --&gt;
&nbsp;&nbsp;&lt;/div&gt;
&lt;/div&gt;</pre>

<p>Es gibt also einen umfassenden Container, darin befindet sich eine unsortierte Liste als Menü und darunter die einzelnen Kategorien. Die Listenpunkte sind mit dem HTML5 Attribut <code>data-id</code> ausgestattet um klar zu machen, welchen Punkt sie einblenden.</p>

<p>jQuery arbeitet auf grandiose Art und Weise damit zusammen, dazu gleich mehr.</p>

<h2>Eine Zeile jQuery</h2>

<p>Hier kommt sie:</p>

<pre>$('.categories&gt;ul li').live('click', function() { $(this).closest('.categories').find('.category').hide().filter('#category'+$(this).data('id')).show().end().end().end().siblings('li').removeClass('active').end().addClass('active');}).filter(':first').click();</pre>

<p>Auch wenn ich große Töne gespuckt habe von wegen eine einzige Zeile, würde ich doch empfehlen ein paar Zeilenumbrüche einzubauen. In Javascript müssen die Zeilen nicht mit einem Simikolon beendet werden, deshalb kann man diese Zeile auch übersichtlicher notieren:</p>

<pre>$('.categories&gt;ul li')
&nbsp;&nbsp;&nbsp;&nbsp;.live('click', function() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(this)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.closest('.categories')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.find('.category')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.hide()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.filter('#category'+$(this).data('id'))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.show()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.end()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.end()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.end()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.siblings('li')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.removeClass('active')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.end()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.addClass('active');
&nbsp;&nbsp;&nbsp;&nbsp;})
&nbsp;&nbsp;&nbsp;&nbsp;.filter(':first')
&nbsp;&nbsp;&nbsp;&nbsp;.click();</pre>

<h2>Einzelerklärung</h2>

<p>Jetzt gehts los! jQuery basiert immer auf einem <strong>Elementstack</strong>. Das bedeutet man wählt per CSS Selektor eine beliebige Anzahl Elemente aus und wendet darauf beliebig viele Befehle an. In diesem Beispiel werden alle Listenelemente ausgewählt die sich in einer Liste befindet, welche wiederum ein direktes Kindelement eines Elements mit der Klasse <code>.categories</code> ist.</p>

<pre>$('.categories&gt;ul li')</pre>

<p>Würde man das <code>&gt;</code> Zeichen weglassen, würden sich die folgenden Anweisungen auf alle Listen im Element <code>.categories</code> beziehen, was natürlich nicht gewünscht ist.</p>

<p>Jedem Listenelement wird der Eventhandler <code>click</code> zugewiesen:</p>

<pre>.live('click', function() {</pre>

<p>Die großartige Funktion <code>live(event, callback)</code> arbeitet im Gegensatz zu <code>click(callback)</code> auch mit Elementen die nachträglich dem Dom hinzugefügt wurden.</p>

<p>Innerhalb eines Callbacks bezieht sich <code>$(this)</code> auf das spezifische Element welches den Funktionsaufruf ausgelöst hat. Sprich: das angeklickte Listenelement. Das dient als Ausgangspunkt um das umfassende Element <code>.categories</code> in den Elementstack zu laden:</p>

<pre>$(this).closest('.categories')</pre>

<p>Vom Ausgangspunkt <code>$(this)</code> wird das nächstgelegene Element ausgewählt. Sollten sich mehrere Elemente mit der Klasse <code>.categories</code> auf der Seite befinden können wir so sicherstellen, dass das richtige Element behandelt wird.</p>

<p>Aus dem richtigen Element werden alle Elemente der Klasse <code>.category</code> gesucht und ausgeblendet:</p>

<pre>.find('.category').hide()</pre>

<p>Mit <code>find(selector)</code> wird innerhalb der Objekte im Elementstack gesucht. Im Gegensatz zu der Funktion <code>filter(selector)</code> welche die Elemente im Stack durchgeht und nur jene zurück liefert auf die der Selector zutrifft.</p>

<p>Die großartige Methode <code>data(key, value)</code> greift automatisch auf das <code>data</code> Attribut aus dem HTML zu und stellt es zur Verfügung.</p>

<p>Mit diesem Wissen müsste der nächste Schritt klar sein:</p>

<pre>.filter('#category'+$(this).data('id')).show()</pre>

<p>Aus allen ausgewählten und versteckten <code>.category</code> Elementen wird das mit der ID des angeklickten Listenelements ausgewählt und angezeigt.</p>

<p>Mit <code>end()</code> setzt man einen veränderten Elementstack wieder zurück. Wir haben jetzt drei mal <code>end()</code>, für <code>filter()</code>, <code>find()</code> und <code>closest()</code>. Also befinden wir uns wieder beim angeklickten Listenelement.</p>

<pre>.siblings('li')</pre>

<p>Damit werden alle Nachbarn des Listenelements ausgewählt, also alle Einträge in der Liste. Egal welches, keines darf mehr die Klasse <code>active</code> besitzen:</p>

<pre>.removeClass('active').end()</pre>

<p>Im gleichen Zug wird auch die Veränderung durch <code>siblings(selector)</code> zurück gesetzt. Fehlt nur noch das hinzufügen der Klasse zum angeklickten Element:</p>

<pre>.addClass('active');</pre>

<p>Das war es innerhalb des Callbacks. Beim laden der Seite werden alle Kategorien angezeigt, das ist nicht Ziel des Tab Widgets, aber auch leicht zu lösen. Zur Erinnerung: Es wurden alle Listenelemente ausgewählt und jedem Element ein Clickhandler zugewiesen.</p>

<pre>$('.categories&gt;ul li').live('click', function() { /* lange zeile */ })</pre>

<p>Auch die <code>live()</code> Funktion gibt den Elementstack zurück, deshalb brauchen wir nur noch zwei grandiose Funktionen anzuhängen:</p>

<pre>.filter(':first').click();</pre>

<p>In jQuerysprache heißt das: Nimm das erste Element aus deinem Stack und klicke es an. Was dann passiert haben wir gerade ausführlich besprochen. Alle Kategorien werden ausgeblendet, die erste wieder ein und das erste Listenelement mit der Klasse <code>active</code> gekennzeichnet.</p>

<p><strong>Fertig!</strong> Das war ein Tab Widget in mehr oder weniger einer Zeile.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2011/01/17/jquery-super-cool/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Pauls Blog ist schöner geworden 2</title>
		<link>http://www.interaktionsdesigner.de/2011/01/12/pauls-blog-ist-schoner-geworden-2/</link>
		<comments>http://www.interaktionsdesigner.de/2011/01/12/pauls-blog-ist-schoner-geworden-2/#comments</comments>
		<pubDate>Wed, 12 Jan 2011 16:13:23 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Ich]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=750</guid>
		<description><![CDATA[Herzlich Willkommen im neuen, schönen Interaktionsdesigner! Das neue Jahr startet mit einem komplett neuen Theme, weg von grün hin zu knalligem rot. Ganz im Stil der Ape Unit GmbH. Das Theme wurde von unserem Grafiker Tim Herzog entwickelt und von mir umgesetzt. Sehr hilfreich dafür war natürlich mein Eintrag wie ein Entwickler einen WordPress Blog [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Herzlich Willkommen</strong> im neuen, schönen Interaktionsdesigner! Das neue Jahr startet mit einem komplett neuen Theme, weg von grün hin zu knalligem rot. Ganz im Stil der <a title="Ape Unit GmbH Berlin" href="http://www.apeunit.com/">Ape Unit GmbH</a>.</p>

<p>Das Theme wurde von unserem Grafiker <a title="Tim Herzog" href="http://www.apeunit.com/tim-herzog">Tim Herzog</a> entwickelt und von mir umgesetzt. Sehr hilfreich dafür war natürlich mein Eintrag <a title="Wordpress Tutorial für Entwickler" href="http://www.interaktionsdesigner.de/2010/10/02/wie-ein-entwickler-einen-wordpress-blog-aufsetzt/">wie ein Entwickler einen WordPress Blog aufsetzt</a>. Aber es gibt auch ein paar neue Funktionen. Ein paar Highlights und deren Umsetzung will ich natürlich nicht für mich behalten.</p>

<p><span id="more-750"></span></p>

<h2>Sticky Posts</h2>

<p>Über die Visibility lässt sich im Backend ein Post als "sticky" markieren. Die Posts kriegt man über die Funktion <code>get_option('sticky_posts')</code> - den Rückgabewert übergibt man dann dem <code>WP_Query Object</code>. Zum Beispiel so:</p>

<pre>$sticky = new WP_Query(array(
&nbsp;&nbsp;'post__in' =&gt; get_option( 'sticky_posts' ),
&nbsp;&nbsp;'caller_get_posts' =&gt; 1,
&nbsp;&nbsp;'orderby' =&gt; 'modified',
&nbsp;&nbsp;'showposts' =&gt; 6
));</pre>

<p>Fragt man die neusten Einträge ab, werden die Sticky Posts allerdings unabhängig von ihrem Datum ganz oben in der Liste angezeigt. Das kann man verhindern:</p>

<pre>$newest = new WP_Query(array(
&nbsp;&nbsp;'showposts' =&gt; 15,
&nbsp;&nbsp;'ignore_sticky_posts' =&gt; 1,
&nbsp;&nbsp;'caller_get_posts' =&gt; 1
));</pre>

<p>Eigentlich sollte <code>ignore_sticky_posts</code> reichen, aber bei mir hat es nur mit <code>caller_get_posts</code> die erhofte Wirkung erzielt.</p>

<h2>Code und Quelltext</h2>

<p>Der Quelltext wird jetzt schöner dargestellt. Realisiert mit dem <a href="http://code.google.com/p/google-code-prettify/">Google Code Prettify</a>. Zeilennummern und Syntaxhighlighting wird direkt dynamisch erstellt.
<pre>function code_func($atts, $content = null) {
&nbsp;&nbsp;$content = strip_tags($content, 'a,strong');
&nbsp;&nbsp;$content = "&lt;pre&gt;".$content."&lt;/pre&gt;";
&nbsp;&nbsp;while(stristr($content, '&nbsp;&nbsp;')) {
&nbsp;&nbsp;&nbsp;&nbsp;$content = do_shortcode($content);
&nbsp;&nbsp;}
&nbsp;&nbsp;return $content;
}
add_shortcode('code', 'code_func');</pre>
Schön, oder? Tabs habe ich mit dem Shortcode [ tab ] umgesetzt. Ohne Leerzeichen wird es durch zwei geschützte Leerzeichen ersetzt. Damit auch mehrere Tabs hintereinander funktionieren jage ich in der <code>while</code> Schleife den Inhalt solange durch die <code>do_shortcode()</code> Funktion bis kein [ tab ] mehr gefunden wird.</p>

<p>Mit jQuery wird jedem <code>pre</code> Element die Klasse <strong>prettify</strong> zugewiesen und anschließend der Syntaxhighlighter gestartet.</p>

<pre>$('article.single pre').addClass('prettyprint linenums');
prettyPrint();</pre>

<p>Ein anderer lang gehegter Traum habe ich mir mit dem Shortcode [ pre ] erfüllt, mit dem ich endlich Quelltext innerhalb des Fließtextes einbinden kann. Die Umsetzung ist sehr simpel, definiert in der <code>functions.php</code> Datei.</p>

<pre>function pre_func($atts, $content = null) {
&nbsp;&nbsp;return '&lt;pre&gt;'.$content.'&lt;/pre&gt;';
}
add_shortcode('pre', 'pre_func');</pre>

<h2>Der Affe</h2>

<p>In der Einzelansicht steht unter der Sidebar unser kleines Maskotchen und macht den Besucher auf unsere Firma aufmerksam. Scrollt der Benutzer nach unten, heftet er sich an den unteren Bildschirmrand, bis die Kommentare erreicht sind, auf denen er sich nieder lässt. Ein super Effekt, realisiert mit jQuery.</p>

<p>Der Trick liegt im <code>Scroll Event</code> und dem Wechsel zwischen <code>position:relative</code> und <code>fixed</code>. Ich habe eine Funktion geschrieben die den Affen positioniert:</p>

<pre>function posTheApe() {
&nbsp;&nbsp;bottom = $(window).scrollTop()+$(window).height();
&nbsp;&nbsp;if(bottom-336-45 &lt;= aside_y) {
&nbsp;&nbsp;&nbsp;&nbsp;$nav.css({
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;position: 'absolute',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;top: aside_y+350
&nbsp;&nbsp;&nbsp;&nbsp;});
&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;else if(bottom &gt;= footer_y) {
&nbsp;&nbsp;&nbsp;&nbsp;$nav.css({
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;position: 'relative',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;top: ''
&nbsp;&nbsp;&nbsp;&nbsp;});
&nbsp;&nbsp;}
&nbsp;&nbsp;else if($nav.css('position') != 'fixed') {
&nbsp;&nbsp;&nbsp;&nbsp;$nav.css({
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;position: 'fixed',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bottom: 0,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;top: ''
&nbsp;&nbsp;&nbsp;&nbsp;});
&nbsp;&nbsp;}
}</pre>

<p>In Zeile 2 wird der Abstand der unteren Fensterkante zum Seitenanfang gemessen. <code>footer_y</code> und <code>aside_y</code> wurden vorher gesetzt und beinhalten den Abstand des Footers, bzw. der Seitenleiste, zum Seitenanfang. Alles andere ist dann nur noch ein abgleich der Werte.</p>

<h2>Twitter</h2>

<p>In der Seitenleiste werden dynamisch meine neusten Twitter Nachrichten angezeigt. Realisiert mit dem großartigen Plugin <a href="http://tweet.seaofclouds.com/">Tweet!</a> Interessant finde ich die Implementierung der Callbacks. Gewöhnt ist man an die Übergabe einer Funktion im Konfigurationsobjekt:</p>

<pre>$("body").plugin({
&nbsp;&nbsp;callback: function() {
&nbsp;&nbsp;&nbsp;&nbsp;//do something
&nbsp;&nbsp;}
});</pre>

<p>Bei <strong>Tweet!</strong> gibt es diese Option allerdings nicht. Im Quelltext habe ich aber mehrere Aufrufe von <code>trigger('loaded')</code> gefunden, so funktionierts:</p>

<pre>$("body")
&nbsp;&nbsp;.plugin()
&nbsp;&nbsp;.bind('loaded', function() {
&nbsp;&nbsp;&nbsp;&nbsp;//do something
&nbsp;&nbsp;});</pre>

<p>Und funktioniert! Mit dem Callback <code>loaded</code> wird die Höhe der Seitenleiste neu bestimmt um den Affen richtig positionieren zu können. Funktioniert einwandfrei!</p>

<h2>Fazit</h2>

<p>Ein paar Kleinigkeiten hatte Tim noch vorgesehen die ich im Laufe der Zeit anpassen werde. Als nächstes will ich endlich wieder ein paar neue und aktualisierte <strong>TYPO3 Extensions</strong> veröffentlichen, darunter auch der lang ersehnte <strong>Kiwi Slider 2.0</strong>!</p>

<p>Man darf also gespannt sein und den <a href="http://www.interaktionsdesigner.de/feed/">RSS Feed</a> abonnieren. Und nicht vergessen <strong>Feedback</strong> in den Kommentaren zu hinterlassen!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2011/01/12/pauls-blog-ist-schoner-geworden-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>phpMyAdmin Quick Access</title>
		<link>http://www.interaktionsdesigner.de/2010/12/01/phpmyadmin-quick-access/</link>
		<comments>http://www.interaktionsdesigner.de/2010/12/01/phpmyadmin-quick-access/#comments</comments>
		<pubDate>Wed, 01 Dec 2010 14:53:07 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=737</guid>
		<description><![CDATA[Das Problem sind ca. 120 Datenbanken auf meiner lokalen Testumgebung und ich will beim arbeiten stets nur schnell in eine einzige. phpMyAdmin lädt aber länger den Frame mit allen Datenbanken. Seit Ewigkeiten stelle ich mir vor einfach anzufangen den Namen zu tippen und -zack- zur Datenbank weiter geleitet zu werden. So siehts aus: Installation Wer [...]]]></description>
			<content:encoded><![CDATA[<p>Das Problem sind <strong>ca. 120 Datenbanken</strong> auf meiner lokalen Testumgebung und ich will beim arbeiten stets nur schnell in eine einzige. <a title="phpMyAdmin kennt jeder" href="http://www.phpmyadmin.net/home_page/index.php" target="_blank">phpMyAdmin</a> lädt aber länger den Frame mit allen Datenbanken. Seit Ewigkeiten stelle ich mir vor einfach anzufangen den Namen zu tippen und <em>-zack-</em> zur Datenbank weiter geleitet zu werden. So siehts aus:
<img class="aligncenter size-full wp-image-738" title="Bildschirmfoto 2010-11-30 um 19.56.53" src="http://blog.paul-lunow.de/wp-content/uploads/2010/12/Bildschirmfoto-2010-11-30-um-19.56.53.png" alt="Bildschirmfoto 2010-11-30 um 19.56.53" width="869" height="841" />
<span id="more-737"></span></p>

<h2>Installation</h2>

<p>Wer keine Zeit oder Lust hat etwas über die Technik dahinter zu lesen, lädt sich alle Dateien bei <a href="https://github.com/apeunit/pmaqa">GitHub</a> herunter und schiebt sie in einen Ordner den er über seinen Webserver erreicht. Anschließend in der <strong>index.php</strong> den Zugang zur Datenbank und den Pfad zur lokalen phpMyAdmin Installation eintragen.</p>

<p><strong>Fertig!</strong> Aber vorsicht: Es sind absolut keine Sicherheitsmaßnahmen vorhanden, eine Installation auf einem Server würde ich tunlichst <strong>vermeiden</strong>!!</p>

<h2>Die Technik</h2>

<p>Die komplette Seite besteht aus der <strong>index.php</strong> Datei. Im oberen Teil sind ein paar Einstellungen zu treffen. Darunter werden mit <a href="http://de3.php.net/mysql_connect" target="_blank">mysql_connect</a> und <a href="http://de3.php.net/mysql_list_dbs" target="_blank">mysql_list_dbs</a> alle Datenbanken ausgelesen und in <strong>$db_list</strong> gespeichert. Die Funktion <strong>mysql_list_dbs</strong> gibt ein Objekt zurück das mit einer<strong> while()</strong> Schleife durchlaufen werden kann. In Kurzform:</p>

<code>$connection = mysql_connect($daten);
$db_list = mysql_list_dbs($connection);
while($row = mysql_fetch_object($db_list)) {
[tab]echo $row-&gt;Database;
}</code>

<p>Das eigentlich schöne passiert mal wieder mit <strong>jQuery</strong>: das geniale <a href="https://github.com/riklomas/quicksearch" target="_blank">Plugin Quicksearch</a> erlaubt das blitschnelle durchsuchen während der Eingabe. Das einzige was der Entwickler tun muss ist ein <strong>Formularfeld</strong> mit einer zu durchsuchenden Datenmenge (z.B. einer <strong>Tabelle</strong>) verknüpfen:</p>

<code>$('input#db').quicksearch('table tr');</code>

<p>Damit das Formularfeld beim Aufruf der Seite den Fokus erhält erweitert man die Zeile noch um einen einfachen Aufruf:</p>

<code>$('input#db')
[tab].focus()
[tab].quicksearch('table tr');</code>

<h2>Fazit</h2>

<p>Nach dem der erste Schritt geschafft ist, drängen sich natürlich eine ganze Reihe weiterer Ideen auf:</p>

<ul>
    <li>Navigation mit Pfeiltasten</li>
    <li>Automatische Vervollständigung</li>
    <li>Anlegen von neuen Datenbanken</li>
</ul>

<p>Wer Lust hat mitzumachen, ist dazu herzlich auf <a href="https://github.com/apeunit/pmaqa" target="_blank">GitHub</a> herzlich eingeladen. Neue Ideen und Verbesserungsvorschläge gerne in den Kommentaren.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2010/12/01/phpmyadmin-quick-access/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

