<?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>TheGeek.de &#187; Coding</title>
	<atom:link href="http://thegeek.de/c/coding/feed" rel="self" type="application/rss+xml" />
	<link>http://thegeek.de</link>
	<description>WordPress, PHP, JavaScript, Web 2.0, Gaming, Motorräder, Fotografie, Piratenpartei, Privates</description>
	<lastBuildDate>Tue, 09 Mar 2010 16:09:05 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Empfehlung: typeface.js &#8211; TTF und OTF Schriften im Browser verwenden</title>
		<link>http://thegeek.de/empfehlung-typeface-js-ttf-und-otf-schriften-im-browser-verwenden</link>
		<comments>http://thegeek.de/empfehlung-typeface-js-ttf-und-otf-schriften-im-browser-verwenden#comments</comments>
		<pubDate>Tue, 29 Dec 2009 17:49:23 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Coding]]></category>
		<category><![CDATA[fonts]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[opentype]]></category>
		<category><![CDATA[schriftarten]]></category>
		<category><![CDATA[truetype]]></category>
		<category><![CDATA[typeface]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=437</guid>
		<description><![CDATA[Ich habe die letzten zwei Tage für ein Kundenprojekt ein Screendesign in XHTML und CSS umgesetzt. Wichtiger Wunsch des Kunden war dabei, dass die extra für den Kunden entworfene Hausschrift Verwendung in der Webseite findet. Und das nicht zu knapp: Überschriften und vorallem das Menü sollte in der Schriftart &#8220;RKM Headline&#8221; ausgegeben werden.
Um TrueType/OpenType Schriften [...]]]></description>
			<content:encoded><![CDATA[<p>Ich habe die letzten zwei Tage für ein Kundenprojekt ein Screendesign in XHTML und CSS umgesetzt. Wichtiger Wunsch des Kunden war dabei, dass die extra für den Kunden entworfene Hausschrift Verwendung in der Webseite findet. Und das nicht zu knapp: Überschriften und vorallem das Menü sollte in der Schriftart &#8220;RKM Headline&#8221; ausgegeben werden.</p>
<p>Um TrueType/OpenType Schriften in eine Webseite zu integrieren, gibt es verschiedene Möglichkeiten. Einmal wäre da <a href="http://www.mikeindustries.com/sifr">sIFR</a>, was ich aber nicht verwenden wollte, da ich Flash eher mit Abneigung gegenüberstehe und es zudem Probleme mit AdBlockern geben kann. Die nächste Möglichkeit wäre gewesen, es mit CSS3 zu lösen, was aber ebenfalls ausschied, da dies von zu wenig Browsern unterstützt wird.</p>
<p>Nach ein wenig Recherche fand ich allerdings eine mir zusagende Lösung: <a href="http://typeface.neocracy.org/">typeface.js</a> &#8211; ein kleines JavaScript, dass mittels SVG/VML die als TTF oder OTF gelieferte Schriftart im Browser verfügbar macht.<span id="more-437"></span></p>
<p>Der Einsatz ist relativ einfach: Auf der Webseite von typeface können beliebige Schriften (TTF/OTF) in JavaScript Dateien konvertiert werden, die zusammen mit der typeface.js im Header der Seite nach den eigenen CSS-Definitionen eingebunden werden. </p>
<p>Hier ein Beispiel:</p>
<pre class="brush:html">
&lt;head&gt;
	&lt;title&gt;Beispiel&lt;/title&gt;
	&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8"/&gt;
	&lt;link rel="stylesheet" href="style.css" media="screen"/&gt;
	&lt;script type="text/javascript" src="js/typeface-0.14.js"&gt;&lt;/script&gt;
	&lt;script type="text/javascript" src="js/rkm_headline_regular.typeface.js"&gt;&lt;/script&gt;
	&lt;script type="text/javascript" src="js/rkm_headline_bold.typeface.js"&gt;&lt;/script&gt;
&lt;/head&gt;
</pre>
<p>Anhand dieses HTML-Codes wird ein wichtiges Detail bereits deutlich: Jede Schriftvariante (Fett/Kursiv/&#8230;) muss gesondert in eine JavaScript Datei konvertiert werden, denn nur so ist es typeface möglich auch CSS-Angaben wie &#8220;font-weight: bold&#8221; richtig zu interpretieren. Fehlt die Fettschriftvariante der Schriftart, wird der Text nicht umgewandelt. Ein kleiner Stolperstein, aber wer es weiß, für den ist es kein Problem.</p>
<p>Ansonsten ist der weitere Einsatz von typeface einfach: Headline-Tags können per Stylesheet formatiert werden, bei anderen Tags muss eine Style-Angabe im Tag direkt gesetzt sein, Kind-Elemente werden nicht beachtet.</p>
<p>Beispieldefinition eines Headline-Tags:</p>
<pre class="brush:css">
#middle h2 {
	font-size:20px;
	font-weight:normal;
	text-transform:uppercase;
	letter-spacing:1px;
	margin-bottom:18px;
	font-family:'RKM Headline',Arial,Helvetica,sans-serif;
	font-weight:bold;
}
</pre>
<p>Der Tag wird erstmal wie gewöhnlich formatiert, so dass die Überschrift auch schön aussieht, wenn typeface nicht funktioniert. Dann wird per &#8220;font-family&#8221; einfach unsere selbst erzeugte Schriftart &#8220;RKM Headline&#8221; gesetzt, um den Rest kümmert sich das JavaScript.</p>
<p>Möchtest du ein anderes Element als eine Headline mit der Schriftart anzeigen, kann dies auch über das Style-Attribut des Tags gelöst werden:</p>
<pre class="brush:html">
	&lt;a class="typeface-js" style="font-family: 'RKM Headline',Arial,Helvetica,sans-serif;"&gt;Dies ist ein schöner Link&lt;/a&gt;
	&lt;br/&gt;
	&lt;br/&gt;
	&lt;a class="extern_link typeface-js" style="font-family: 'RKM Headline',Arial,Helvetica,sans-serif;"&gt;Dies ist ein schöner externer Link&lt;/a&gt;
</pre>
<p>Hier nur wichtig: Im Class-Attribut des Tags muss &#8220;typeface-js&#8221; vorkommen, der Rest läuft über das Style-Attribut, aber auch die CSS-Attribute &#8211; wie z.B. die Schriftgröße &#8211; die auf das Element wirken werden berücksichtigt.</p>
<p>Schon klasse muss ich sagen&#8230; und OpenSource noch dazu! Daumen hoch für typeface!</p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/empfehlung-typeface-js-ttf-und-otf-schriften-im-browser-verwenden/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Per RegEx geraden und ungeraden Tabellen-Zeilen ensprechende CSS-Klassen zuweisen</title>
		<link>http://thegeek.de/per-regex-geraden-und-ungeraden-tabellen-zeilen-ensprechende-css-klassen-zuweisen</link>
		<comments>http://thegeek.de/per-regex-geraden-und-ungeraden-tabellen-zeilen-ensprechende-css-klassen-zuweisen#comments</comments>
		<pubDate>Wed, 23 Dec 2009 12:12:04 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[regex]]></category>
		<category><![CDATA[tabellen]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=426</guid>
		<description><![CDATA[Wer vor dem Problem steht, dass ein Kunde bei einer Web-Anwendung unbedingt Tabellen-Zeilen mit wechselnden Farben je gerader und ungerader Zeile wünscht und dafür ca. 200 Kilobyte Quellcode überarbeiten müsste, der kann es sich ein wenig vereinfachen, wenn folgender Code vor der Ausgabe auf den auszugebenden Inhalt angewendet wird.
Das Skript durchsucht mit zwei kleinen Regular [...]]]></description>
			<content:encoded><![CDATA[<p>Wer vor dem Problem steht, dass ein Kunde bei einer Web-Anwendung unbedingt Tabellen-Zeilen mit wechselnden Farben je gerader und ungerader Zeile wünscht und dafür ca. 200 Kilobyte Quellcode überarbeiten müsste, der kann es sich ein wenig vereinfachen, wenn folgender Code vor der Ausgabe auf den auszugebenden Inhalt angewendet wird.<span id="more-426"></span></p>
<p>Das Skript durchsucht mit zwei kleinen Regular Expressions den Inhalt nach Tabellen und weist dann den Tabellen-Zeilen entsprechende Klassen (even/odd) zu. So können alle Tabellen per CSS formatiert werden. Klar leidet darunter die Performance etwas, aber sicherlich nicht viel mehr, als wenn ich in jeder Schleife in der eine Tabelle aufgebaut wird ein Zähler mitlaufen lasse und eine Bedingsabfrage mache.</p>
<pre class="brush:php">
	// Convert table rows to even/odd class
	preg_match_all( "/&lt;table.*&gt;(.*)&lt;\/table&gt;/siU", $html, $matches );
	if( $matches )
	{
		foreach( $matches[ 1 ] AS $tbody )
		{
			$new_rows = '';
			if( preg_match_all( "/&lt;tr.*&gt;.+&lt;\/tr&gt;/siU", $tbody, $tbmatches ) )
			{
				$i = 0;
				foreach( $tbmatches[ 0 ] AS $tr )
				{
					// Ignore rows containing th cells
					if( strpos( $tr, '&lt;th' ) === false )
					{
						if( $i % 2 == 0 )
							$new_rows .= str_replace( '&lt;tr', '&lt;tr class="even"', $tr );
						else
							$new_rows .= str_replace( '&lt;tr', '&lt;tr class="odd"', $tr );
						$i++;
					}
					else	$new_rows .= $tr;
				}
				$html = str_replace( $tbody, $new_rows, $html );
			}
		}
	}
</pre>
<p>Im Grunde ganz einfach: Die erste RegEx sucht alle vorhanden Tabellen und deren Inhalt. Danach werden die Zeilen des Inhalts ebenfalls per RegEx ermittelt und per Zeichenersetzung angepasst.</p>
<p>Vielleicht hilft das ja Jemandem irgendwann mal&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/per-regex-geraden-und-ungeraden-tabellen-zeilen-ensprechende-css-klassen-zuweisen/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Spaß mit der Twitter API und Ausdruck des Protests gegenüber Harley Davidson</title>
		<link>http://thegeek.de/spas-mit-der-twitter-api-und-ausdruck-des-protests-gegenuber-harley-davidson</link>
		<comments>http://thegeek.de/spas-mit-der-twitter-api-und-ausdruck-des-protests-gegenuber-harley-davidson#comments</comments>
		<pubDate>Wed, 09 Dec 2009 12:54:30 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[buell]]></category>
		<category><![CDATA[harley davidson]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[protest]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=398</guid>
		<description><![CDATA[@moto1203 hat mich über Twitter kontaktiert und gefragt, ob es nicht irgendwie möglich sei ein Programm zu schreiben, dass bei bestimmten Hashtags eine @reply erzeugt. Thematisch ging&#8217;s konkret um den bekannten Motorradhersteller &#8220;Harley Davidson&#8221;, der kürzlich die Tochter- und Traditionsfirma &#8220;BUELL&#8221; einfach so dicht gemacht hat. Buell Motorräder wurden &#8220;nicht oft genug&#8221; verkauft, was aber [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://twitter.com/moto1203">@moto1203</a> hat mich über Twitter kontaktiert und gefragt, ob es nicht irgendwie möglich sei ein Programm zu schreiben, dass bei bestimmten Hashtags eine @reply erzeugt. Thematisch ging&#8217;s konkret um den bekannten Motorradhersteller &#8220;Harley Davidson&#8221;, der kürzlich die Tochter- und Traditionsfirma &#8220;BUELL&#8221; einfach so dicht gemacht hat. Buell Motorräder wurden &#8220;nicht oft genug&#8221; verkauft, was aber nichts daran ändert, das die Kisten ihren Markt hatten. Das fanden wir jedenfalls schon ziemlich kacke von Harley Davidson.</p>
<p>Also habe ich kurzerhand einen neuen Twitter-Account mit dem klangvollen Namen &#8220;<a href="http://twitter.com/subversives">@subversives</a>&#8221; erstellt und ein kleines PHP-Skript geschrieben, dass neue Tweets mit einem #harley Hashtag sucht und eine zufällig ausgewählte Antwort erstellt. Natürlich konfigurierbar. :-)<span id="more-398"></span></p>
<p>Dazu gibt es zwei kleine Funktionen. Die erste Funktion sucht Tweets nach einem bestimmten Suchbegriff:</p>
<pre class="brush:php">
// Twitter search api
function twt_search( $username, $password, $search, $since_id = 0, $rpp = 30, $page = 1 )
{
	// Curl init
	$curl = curl_init();

	// Curl basic settings
	curl_setopt( $curl, CURLOPT_URL, 'http://search.twitter.com/search.json' );
	curl_setopt( $curl, CURLOPT_RETURNTRANSFER, 1 );
	curl_setopt( $curl, CURLOPT_USERPWD, "$username:$password" );
	curl_setopt( $curl, CURLOPT_POST, true );

	// Build POST parameters
	$post_arr = array();
	$post_arr[] = "q=" . urlencode( $search );
	if( !empty( $since_id ) )
		$post_arr[] = "since_id=" . $since_id;
	if( !empty( $rpp ) )
		$post_arr[] = "rpp=" . $rpp;
	if( !empty( $page ) )
		$post_arr[] = "page=" . $page;
	curl_setopt( $curl, CURLOPT_POSTFIELDS, implode( '&#038;', $post_arr ) );

	// Exec, set return
	$return = json_decode( curl_exec( $curl ) );

	// Close curl
	curl_close( $curl );

	return $return;
}
</pre>
<p>Übergeben werden Benutzername, Passwort, der Suchbegriff und &#8211; wenn bekannt &#8211; auch die &#8220;since_id&#8221;, welche es ermöglicht nur Tweets mit einer höheren ID zu ermitteln. Das ist für unser lustiges Protest-Skript wichtig, denn wir wollen die Leute ja nicht zuspammen und immer wieder auf die gleichen Tweets antworten. Nur neue Tweets seit der letzten Suche sollen berücksichtigt werden, also merken wir uns einfach die höchste Tweet ID und übergeben diese wieder bei der nächsten Suche. Der Parameter &#8220;rpp&#8221; steht übrigens für &#8220;results per page&#8221; &#8211; mit der Voreinstellung werden also maximal 30 Tweets zurückgegeben.</p>
<p>Technisch wird die Abfrage über die CURL-Bibliothek realisiert, theoretisch ginge es aber auch mit &#8220;file_get_contents&#8221; oder &#8220;fopen&#8221;, aber ich mag CURL. Ist ganz praktisch.</p>
<p>Die zweite benötigte Funktion erstellt über die Twitter API einen neuen Tweet. Auch hier stehen wieder einige Parameter zur Verfügung:</p>
<pre class="brush:php">
// Twitter update api
function twt_update( $username, $password, $status, $in_reply_to_status_id = '', $lat = '', $long = '' )
{
	// Curl init
	$curl = curl_init();

	// Curl basic settings
	curl_setopt( $curl, CURLOPT_URL, 'http://twitter.com/statuses/update.json' );
	curl_setopt( $curl, CURLOPT_RETURNTRANSFER, 1 );
	curl_setopt( $curl, CURLOPT_USERPWD, "$username:$password" );
	curl_setopt( $curl, CURLOPT_POST, true );

	// Build POST parameters
	$post_arr = array();
	$post_arr[] = "status=" . urlencode( $status );
	if( !empty( $in_reply_to_status_id ) )
		$post_arr[] = "in_reply_to_status_id=" . $in_reply_to_status_id;
	if( !empty( $lat ) )
		$post_arr[] = "lat=" . $lat;
	if( !empty( $long ) )
		$post_arr[] = "long=" . $long;
	curl_setopt( $curl, CURLOPT_POSTFIELDS, implode( '&#038;', $post_arr ) );

	// Exec, set return
	$return = json_decode( curl_exec( $curl ) );

	// Close curl
	curl_close( $curl );

	return $return;
}
</pre>
<p>Neben Nutzername und Passwort können an diese Funktion der Statustext (Tweet) und der sehr wichtige Parameter &#8220;in_reply_to_status_id&#8221; übergeben werden. Wird die ID eines Tweets mit diesem Parameter übergeben, erkennt Twitter, dass es sich um eine @rely zu dem Tweet mit der übergebenen ID handelt. Da wir ja Antworten senden wollen, genau das richtige! Die Parameter &#8220;lat&#8221; und &#8220;long&#8221; sind übrigens nur schmückendes Beiwerk und werden von mir nicht genutzt. Ich habe das nur der Vollständigkeit halber mit rein genommen.</p>
<p>Nun zur Anwendung der Funktionen:</p>
<pre class="brush:php">
// Twitter account settings
$username = 'user';
$password = 'pass';

// Configure some reply variations in english and german
$replys_en = array(
	'Always remember #BUELL if you talk about Harley Davidson!',
	'Hey, remember #BUELL if you talk about Harley Davidson!',
	'Remember #BUELL FOREVER! Harley Davidson? NEVER!',
	'It makes me sick, that you dont talk about #BUELL ;-)',
	'#BUELL #BUELL #BUELL remember the Harley Davidson #FAIL',
	'#BUELL killed by Harley Davidson in 2k9. Remember that!',
	'#BUELL will never die. Harley Davidson will.'
);
$replys_de = array(
	'Erinner dich an #BUELL wenn du über Harley Davidson sprichst!',
	'Harley Davidson? Die Firma, die #BUELL zerstört hat?',
	'#BUELL FOREVER! Harley Davidson? NEVER!',
	'Es macht mich krank, dass nicht auch über #BUELL sprichst!',
	'#BUELL #BUELL #BUELL denk an den Harley Davidson #FAIL',
	'#BUELL wurde von Harley Davidson 2k9 geschlossen. HD is next!',
	'#BUELL wird niemals sterben, aber Harley Davidson. #Rentnerchopper'
);

// Load last parsed tweet id
if( file_exists( 'harley_since_id.dat' ) )
	$harley_since_id = file_get_contents( 'harley_since_id.dat' );
else
	$harley_since_id = 0;

// Search for tag harley
$harley = twt_search( $username, $password, '#harley', $harley_since_id );
if( is_object( $harley ) )
{
	if( count( $harley -> results ) )
	{
		foreach( $harley -> results AS $rkey => $tweet )
		{
			// Descending order, so the first array element has the highest id!
			if( $rkey == 0 )
				$harley_since_id = $tweet -> id;
			// Only reply if buell not found
			if( stripos( $tweet -> text, 'buell' ) === false &#038;&#038; $tweet -> from_user != $username )
			{
				if( $tweet -> iso_language_code != 'de' )
					$reply = "@{$tweet->from_user} " . $replys_en[ array_rand( $replys_en ) ];
				else
					$reply = "@{$tweet->from_user} " . $replys_de[ array_rand( $replys_de ) ];

				echo "$reply\n";

				// Send reply
				twt_update( $username, $password, $reply, $tweet -> id );
			}
		}
	}
	else	echo "No new tweets to tag #harley\n";
}

// Store last parsed tweet id
file_put_contents( 'harley_since_id.dat', $harley_since_id );
</pre>
<p>Zuerst werden in zwei Arrays englische bzw. deutsche Ausdrücke des Protests definiert, danach wird aus einer kleinen Datendatei die ID des letzten gefundenen Tweets geladen und die Suche ausgeführt.<br />
Die Suchfunktion gibt ein Objekt zurück, dass in der Eigenschaft &#8220;results&#8221; die gefundenen Tweets als Array enthält, welches anschließend durchlaufen wird. Beim ersten gefundenen Tweet wird die &#8220;since_id&#8221; neu gesetzt. Warum beim ersten? Na, weil die Tweets absteigend sortiert sind &#8211; der Erste ist also immer der Aktuellste.<br />
Enthält der Tweet nicht das Wort &#8220;buell&#8221;, wird in der entsprechenden Sprache (deutsch oder englisch) eine @reply an den Twitter-Account des Tweets gesendet.</p>
<p>Tja, das war&#8217;s eigentlich schon. Wer es mal probieren und einen Spruch reingedrückt bekommen will, der zwitschert einfach mal was mit dem Hashtag #harley &#8211; es dauert allerdings ein wenig, bis die Antwort kommt, das Skript läuft nur alle 15 Minuten.</p>
<p>Ich bin gespannt, wie lange der Account aktiv ist, ohne als Spam gemeldet zu werden. ;-)</p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/spas-mit-der-twitter-api-und-ausdruck-des-protests-gegenuber-harley-davidson/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Interessantes Menü mit CSS Rotation</title>
		<link>http://thegeek.de/interessantes-menu-mit-css-rotation</link>
		<comments>http://thegeek.de/interessantes-menu-mit-css-rotation#comments</comments>
		<pubDate>Tue, 08 Dec 2009 12:06:02 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[menüs]]></category>
		<category><![CDATA[programmieren]]></category>
		<category><![CDATA[rotation]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=390</guid>
		<description><![CDATA[Gestern habe ich einen Artikel über Rotation von HTML Elementen mittels CSS auf snook.ca gelesen und da kam mir die Idee, dass mit diesen CSS-Anweisungen ja auch ein stylisches Menü gebastelt werden kann. Also habe ich mich gestern Abend kurz an den Rechner gesetzt und ein wenig gespielt. Nach anfänglichen Problemen im FireFox &#8211; was [...]]]></description>
			<content:encoded><![CDATA[<p>Gestern habe ich einen Artikel über Rotation von HTML Elementen mittels CSS auf <a href="http://snook.ca/archives/html_and_css/css-text-rotation">snook.ca</a> gelesen und da kam mir die Idee, dass mit diesen CSS-Anweisungen ja auch ein stylisches Menü gebastelt werden kann. Also habe ich mich gestern Abend kurz an den Rechner gesetzt und ein wenig gespielt. Nach anfänglichen Problemen im FireFox &#8211; was ich nicht erwartet hätte, ich dachte eher der IE spackt mal wieder rum &#8211; hat es mit meinem 90° gegen den Uhrzeigersinn gedrehtem Menü auch hingehauen.</p>
<p>Viel braucht es wirklich nicht, nur ein wenig HTML und ein wenig CSS, wobei der HTML-Code für das Menü absoluter Standard-Code ist, der auch für ein Top-Menü Verwendung finden würde.<span id="more-390"></span></p>
<pre class="brush:html">
<div id="menucontainer">
<div id="menu">
		<a href="#1">Home</a>
		<a href="#2">Weblog</a>
		<a href="#3">Infos</a>
		<a href="#4">Pornos</a>
		<a href="#5">Impressum</a>
	</div>
</div>
</pre>
<p>Der &#8220;menucontainer&#8221; ist übrigens überflüssig, den habe ich nur verwendet, weil ich das Menü nicht zentrieren, sondern etwas versetzt nach links anzeigen wollte.</p>
<p>Klarer wird es sichlich mit dem folgenden CSS, welches das Menü darstellt:</p>
<pre class="brush:css">
* {
	margin: 0em;
	padding: 0em;
	border: none;
}
#menucontainer {
	width: 800px;
	margin: auto auto;
}
#menu {
	width: 200px;
	-webkit-transform: rotate( -90deg );
	-moz-transform: rotate( -90deg );
	-moz-transform-origin: 100px 100px;
	filter: progid:DXImageTransform.Microsoft.BasicImage( rotation=3 );
}
#menu a:link, #menu a:visited {
	background-color: #F00;
	color: #FFF;

	margin-bottom: 25px;
	width: 200px;
	height: 50px;
	padding: 5px;
	line-height:90%;
	display: block;

	font-family: sans-serif;
	font-weight: bold;
	font-size: 24px;
	text-decoration: none;
}
#menu a:hover {
	background-color: #DDD;
	color: #F00;
}
</pre>
<p>Wenn ich ein CSS-Stylesheet beginne, schalte ich zuerst für alle Elemente die margins, paddings und die borders aus, um sie später für die Elemente wieder zu setzen, wo ich diese Eigenschaften wirklich brauche. Das macht die ganze Sache immer klarer und behebt viele Probleme mit dem IE auf einen Schlag.</p>
<p>Dem div &#8220;menucontainer&#8221; wird dann eine Breite von 800 Pixeln zugewiesen und ein automatischer margin, wodurch das gesamte div element im Browser zentriert wird.</p>
<p>Dann kommt schon die Anweidung, die das Menü gegen den Uhrzeigersinn dreht. Zuerst wird eine Breite vergeben, die der Breite der einzelnen Menüpunkte entspricht. Das muss so sein, sonst funktioniert es im IE 7 nicht.<br />
Danach folgen Anweisungen für die verschiedenen Browser um die Rotation durchzuführen. Wichtig beim FireFox: &#8220;-moz-transform-origin&#8221; muss korrekt gesetzt werden, sonst sitzen die Menüpunkte später zu tief. Jeweils die Hälfte der Menüpunkt-Breite für horizontalen und vertikalen Wert haben sich bei mir bewährt.</p>
<p>Die einzelnen Menüpunkt können beliebig formatiert werden, auch margins und paddings sind kein Problem. Wichtig ist allerdings, dass &#8220;display&#8221; auf &#8220;block&#8221; gesetzt wird und feste Breiten und Höhen vergeben werden, sonst wird es Probleme bei der Darstellung geben.</p>
<p>Getestet habe ich die Anweisungen im IE 7 und im FireFox 3.5. Im IE 6 läufts so lala, könnte man sicherlich auch noch hinbekommen, aber ich bin der Meinung, dass der IE 6 nicht mehr unterstützt werden muss. Wer den IE 6 noch nutzt, der fährt auch Autos ohne Bremsen.</p>
<p><a href="http://www.codemonster.de/source/menu_rotation_test.php" target="_blank">Hier gibt&#8217;s die komplette Datei</a> und hier eine kleine Vorschau, wie es aussehen könnte:</p>
<style type="text/css">
	#rotationtest_menucontainer {
		width: 800px;
		margin: auto auto;
	}
	#rotationtest_menu {
		width: 200px;
		-webkit-transform: rotate( -90deg );
		-moz-transform: rotate( -90deg );
		-moz-transform-origin: 100px 100px;
		filter: progid:DXImageTransform.Microsoft.BasicImage( rotation=3 );
	}
	#rotationtest_menu a:link, #rotationtest_menu a:visited {
		background-color: #F00;
		color: #FFF;</p>
<p>		margin-bottom: 25px;
		width: 200px;
		height: 50px;
		padding: 5px;
		line-height:90%;
		display: block;</p>
<p>		font-family: sans-serif;
		font-weight: bold;
		font-size: 24px;
		text-decoration: none;
	}
	#rotationtest_menu a:hover {
		background-color: #DDD;
		color: #F00;
	}
</style>
<div id="rotationtest_menucontainer">
<div id="rotationtest_menu">
		<a href="#1">Home</a><br />
		<a href="#2">Weblog</a><br />
		<a href="#3">Infos</a><br />
		<a href="#4">Pornos</a><br />
		<a href="#5">Impressum</a>
	</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/interessantes-menu-mit-css-rotation/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tab-Menüs mit Prototype generalisieren</title>
		<link>http://thegeek.de/tab-menus-mit-prototype-generalisieren</link>
		<comments>http://thegeek.de/tab-menus-mit-prototype-generalisieren#comments</comments>
		<pubDate>Fri, 27 Nov 2009 14:37:56 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[menüs]]></category>
		<category><![CDATA[prototype]]></category>
		<category><![CDATA[tabbing]]></category>
		<category><![CDATA[tabs]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=367</guid>
		<description><![CDATA[Wer kennt es nicht: Mehrere Datentabellen oder -abschnitte auf einer Seite und der Benutzer verliert schnell den Überblick. Die Lösung: Ein wenig JavaScript, mit ein wenig CSS und ein paar DIVs garniert, das ganze kräftig durchkneten und fertig ist der Tabbed-Content für jeden Einsatzzweck. 
Hier ein wenig HTML:


Datenblatt 1
Datenblatt 2
Datenblatt 3
Datenblatt 4
Datenblatt 5

Jede Menge Daten [...]]]></description>
			<content:encoded><![CDATA[<p>Wer kennt es nicht: Mehrere Datentabellen oder -abschnitte auf einer Seite und der Benutzer verliert schnell den Überblick. Die Lösung: Ein wenig JavaScript, mit ein wenig CSS und ein paar DIVs garniert, das ganze kräftig durchkneten und fertig ist der Tabbed-Content für jeden Einsatzzweck. <span id="more-367"></span></p>
<p>Hier ein wenig HTML:</p>
<pre class="brush:html">
<div id="tabmenu">
<div id="tab_datasheet1" class="tab active">Datenblatt 1</div>
<div id="tab_datasheet2" class="tab">Datenblatt 2</div>
<div id="tab_datasheet3" class="tab">Datenblatt 3</div>
<div id="tab_datasheet4" class="tab">Datenblatt 4</div>
<div id="tab_datasheet5" class="tab">Datenblatt 5</div>
</div>
<div id="datasheet1">Jede Menge Daten (1)</div>
<div id="datasheet2" style="display:none">Jede Menge Daten (2)</div>
<div id="datasheet3" style="display:none">Jede Menge Daten (3)</div>
<div id="datasheet4" style="display:none">Jede Menge Daten (4)</div>
<div id="datasheet5" style="display:none">Jede Menge Daten (5)</div>
</pre>
<p>Oben findet sich unser Tab-Menü, dass die insgesamt 5 Daten-Layer per Klick einblenden soll. Die DIVs mit den Daten sind per Style-Definition erstmal nicht sichtbar, bis auf den ersten DIV, da davon auszugehen ist, dass ohne einen Klick auf etwas das erste Datenblatt angezeigt werden soll. Damit das Tab-Menü auch ansprechend aussieht, brauchen wir noch folgende CSS Definitionen:</p>
<pre class="brush:css">
#tabmenu {
	overflow:hidden;
	border-bottom:1px solid #FFF;
}
#tabmenu .tab {
	float:left;
	border:1px solid #660000;
	border-bottom:none;
	margin-left:3px;
	padding:3px;
	background-color:#F4F4F4;
	font-weight:bold;
}
#tabmenu .active {
	background-color:#FFFFFF;
	color:#000099;
}
#tabmenu .tab:hover {
	background-color:#FFFFFF;
	cursor:pointer;
}
</pre>
<p>Damit wir nun nicht für jeden einzelnen Tab eine &#8220;onclick&#8221; Aktion schreiben müssen, habe ich mir überlegt ein auf Prototype aufsetzendes JavaScript zu schreiben, dass anhand der verwendeten IDs der Tabs und der Daten-DIVs (die nur zueinander passen müssen) eine generell einsetzbare Lösung schafft. Das Skript kann im Head-Bereich der Seite eingebunden werden und durchsucht beim Aufruf, ob Tabs vorhanden sind und behandelt diese entsprechend.</p>
<pre class="brush:js">
/**
 * Render a tabbed menu
 */
var tabids = [];
var containerids = [];
function create_tabs()
{
	$$('.tab').all( function( el ) {
			tabids.push( el.id );
			containerids.push( el.id.replace( 'tab_', '' ) );
			el.observe( 'click', handle_tab_click );
			return true;
	} );
}
/**
 * Hande a clicked tab
 */
function handle_tab_click( event )
{
	// Get container id
	containerid = this.id.replace( 'tab_', '' );
	// Set active tab menu point
	tabids.all( function( tab ) {
		$(tab).removeClassName( 'active' );
		return true;
	} );
	this.addClassName( 'active' );
	// Set active tab content container
	containerids.all( function( container ) {
		$(container).hide();
		return true;
	} );
	$(containerid).show();
}
/**
 * Init tabbing
 */
Event.observe( window, 'load', create_tabs );
</pre>
<p>Die erste Funktion &#8220;create_tabs&#8221; sucht alle DIV-Layer innerhalb der Seite, die mit der CSS-Klasse &#8220;tab&#8221; versehen sind. Die gefundenen Tabs werden danach zur weiteren Verarbeitung in einem Array gespeichert und mit einer String-Ersetzung der zugehörige Daten-Layer ermittelt. Die IDs der Datenlayer werden ebenfalls in einem Array gespeichert. Zu guter letzt wird dem Tab-Menüpunkt noch eine Handler-Funktion zugewiesen.</p>
<p>Die zweite Funktion ist diese Handler-Funktion. Beim Klick wird zuerst ermittelt, welcher Daten-Layer angezeigt werden soll, indem durch eine Zeichenersetzung das &#8220;tab_&#8221; in der ID des Tab-Menüpunkts entfernt wird. Übrig bleibt dann z.B. &#8220;datasheet1&#8243;, wenn der erste Menüpunkt ausgewählt wurde. So weiß die Funktion für den späteren Verlauf, welcher DIV angezeigt werden muss.</p>
<p>Nun geht es daran, das Tab-Menü entsprechend zu verändern, denn es soll ja der angeklickte Menüpunkt hervorgehoben werden. Dazu entfernen wir per Prototype-Methode &#8220;all&#8221;, die auf das bei der Initialisierung erstellte Array angewendet wird, bei allen Tabs die CSS Klasse &#8220;active&#8221;. Danach wir die Klasse &#8220;active&#8221; dann beim angeklickten Punkt gesetzt und das Menü ändert sich so entsprechend dem Nutzerverhalten.</p>
<p>Dann durchlaufen wir ebenfalls mit &#8220;all&#8221; das Array, das die IDs der Datenblätter enthält und verstecken mittels &#8220;hide&#8221; alle DIVs. Nun wird nur noch das richtige DIV eingeblendet und das Tabbing ist komplett.</p>
<p>Großes Finale im Skript ist dann noch ein Event-Observer, der nach dem Laden der Seite die Funktion &#8220;create_tabs&#8221; aufruft und so alle auf der Seite gefundenen Tabs initialisiert.</p>
<p>Wichtig für den Einsatz des Skripts ist nur folgendes: Die IDs der Tab-Menüpunkt und der Layer mit den Daten müssen auf einander abgestimmt sein und ein Tab-Menüpunkt muss immer mit &#8220;tab_&#8221; beginnen. Lege ich also einen Tab mit der ID &#8220;tab_datentabelle123&#8243; an, dann muss das DIV mit den Daten die ID &#8220;datentabelle123&#8243; haben, sonst funktioniert es nicht. Natürlich müssen die Tab-Menüpunkte auch die richtigen CSS-Klassen haben, aber das versteht sich wohl von selbst.</p>
<p>Und so könnte es aussehen:</p>
<div id="tabmenu">
<div id="tab_datasheet1" class="tab active">Datenblatt 1</div>
<div id="tab_datasheet2" class="tab">Datenblatt 2</div>
<div id="tab_datasheet3" class="tab">Datenblatt 3</div>
<div id="tab_datasheet4" class="tab">Datenblatt 4</div>
<div id="tab_datasheet5" class="tab">Datenblatt 5</div>
</div>
<div id="datasheet1">Jede Menge Daten (1)</div>
<div id="datasheet2" style="display:none">Jede Menge Daten (2)</div>
<div id="datasheet3" style="display:none">Jede Menge Daten (3)</div>
<div id="datasheet4" style="display:none">Jede Menge Daten (4)</div>
<div id="datasheet5" style="display:none">Jede Menge Daten (5)</div>
<style type="text/css">
#tabmenu {
	overflow:hidden;
	border-bottom:1px solid #FFF;
}
#tabmenu .tab {
	float:left;
	border:1px solid #660000;
	border-bottom:none;
	margin-left:3px;
	padding:3px;
	background-color:#F4F4F4;
	font-weight:bold;
}
#tabmenu .active {
	background-color:#FFFFFF;
	color:#000099;
}
#tabmenu .tab:hover {
	background-color:#FFFFFF;
	cursor:pointer;
}
</style>
<p><script type="text/javascript">
/**
 * Render a tabbed menu
 */
var tabids = [];
var containerids = [];
function create_tabs()
{
	$$('.tab').all( function( el ) {
			tabids.push( el.id );
			containerids.push( el.id.replace( 'tab_', '' ) );
			el.observe( 'click', handle_tab_click );
			return true;
	} );
}
/**
 * Hande a clicked tab
 */
function handle_tab_click( event )
{
	// Get container id
	containerid = this.id.replace( 'tab_', '' );
	// Set active tab menu point
	tabids.all( function( tab ) {
		$(tab).removeClassName( 'active' );
		return true;
	} );
	this.addClassName( 'active' );
	// Set active tab content container
	containerids.all( function( container ) {
		$(container).hide();
		return true;
	} );
	$(containerid).show();
}
/**
 * Init tabbing
 */
create_tabs();
</script></p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/tab-menus-mit-prototype-generalisieren/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>WordPress und lighttpd, Permalinks mit URL rewriting</title>
		<link>http://thegeek.de/wordpress-und-lighttpd-permalinks-mit-url-rewriting</link>
		<comments>http://thegeek.de/wordpress-und-lighttpd-permalinks-mit-url-rewriting#comments</comments>
		<pubDate>Tue, 24 Nov 2009 11:54:00 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[htaccess]]></category>
		<category><![CDATA[lighttpd]]></category>
		<category><![CDATA[permalinks]]></category>
		<category><![CDATA[regex]]></category>
		<category><![CDATA[rewrite]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=355</guid>
		<description><![CDATA[Ich nutze schon seit langem keinen Apache Webserver mehr, sondern lighttpd, da dieser schlank und performant ist. Einziger Nachteil ist in meinen Augen die fehlende Kompatibilität zu &#8220;.htaccess&#8221; Dateien, die bei vielen Open-Source Web-Anwendungen oft bereits mitgeliefert werden, um z.B. die URL&#8217;s für Suchmaschinen zu optimieren. Bei WordPress wird diese Funktion über die sogenannte &#8220;Permalink [...]]]></description>
			<content:encoded><![CDATA[<p>Ich nutze schon seit langem keinen Apache Webserver mehr, sondern <a href="http://www.lighttpd.net/">lighttpd</a>, da dieser schlank und performant ist. Einziger Nachteil ist in meinen Augen die fehlende Kompatibilität zu &#8220;.htaccess&#8221; Dateien, die bei vielen Open-Source Web-Anwendungen oft bereits mitgeliefert werden, um z.B. die URL&#8217;s für Suchmaschinen zu optimieren. Bei WordPress wird diese Funktion über die sogenannte &#8220;Permalink Struktur&#8221; realisiert. Einfach erklärt: Mittels URL rewrite wird eine eigentlich nicht existente URL trotzdem an die Web-Anwendung übergeben, ohne einen 404 Status Header zu senden. WordPress kann den passenden Inhalt dann anhand der definierten Permalink Struktur laden und anzeigen. Diese Funktionalität wollte ich bei keinem meiner Blogs missen und kann glücklicherweise auch recht einfach für lighttpd umgesetzt werden.<span id="more-355"></span></p>
<p>Lighttpd bietet hierfür die Möglichkeit in einem virtuellen Host eine URL rewrite Regel zu definieren. Im VHost von thegeek.de sieht das z.B. so aus:</p>
<pre class="brush:plain">
# Auszug aus dem thegeek.de VHost
$HTTP["host"] =~ "(^www\.thegeek\.de)|(^thegeek\.de)" {
	url.rewrite =	(
				"^(/gallery/|/wp-.*|/xmlrpc\.php|/robots\.txt|/sitemap\.xml|.*\?album=[0-9]+&#038;gallery=[0-9]+|.*\?p=[0-9]+|.*\?cat=[0-9]+|.*\?feed=|.*\?s=).*$" => "$0",
				"^" => "index.php"
			)
}
</pre>
<p>Die erste Regel greift bei den URL-Parametern des NextGen Gallery Plugins, den WordPress internen Verzeichnissen und Parametern, der Google-Sitemap, der robots.txt, sowie der XML-RPC und Feed Schnittstelle. Trifft die Regel zu, wird die URL auf keinen Fall umgeschrieben und so wie sie ist weitergegeben. Dies ist absolut notwendig, denn sonst würde z.B. &#8220;thegeek.de/wp-admin&#8221; auch umgeleitet und das Backend könnte nicht mehr aufgerufen werden.</p>
<p>Die zweite Regel leitet alle restlichen URL&#8217;s zur Index Datei von WordPress um, welche die URL dann interpretieren kann, um anhand der Permalink Struktur den richtigen Inhalt zu finden.</p>
<p>Im Grunde recht einfach und vorallem: Es funktioniert prima.</p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/wordpress-und-lighttpd-permalinks-mit-url-rewriting/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Parallax Scrolling Effekt mit Prototype/Scriptaculous JavaScript</title>
		<link>http://thegeek.de/parallax-scrolling-effekt-mit-prototypescriptaculous-javascript</link>
		<comments>http://thegeek.de/parallax-scrolling-effekt-mit-prototypescriptaculous-javascript#comments</comments>
		<pubDate>Wed, 11 Nov 2009 10:09:57 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[eyecandy]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[parallax]]></category>
		<category><![CDATA[prototype]]></category>
		<category><![CDATA[scriptaculous]]></category>
		<category><![CDATA[scrolling]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=325</guid>
		<description><![CDATA[Wer sich an Spiele wie &#8220;Shadow of the Beast&#8221; erinnert, der muss sich auch zwangsweise an diesen netten Pseudo-3D Effekt erinnern, mit dem diese Spiele ihren coolen Look erhielten. Parallax Scrolling nennt man diese Technik übrigens, bei der verschiedene Layer aus Grafiken übereinander gelegt und unterschiedlich schnell horizontal oder auch vertikal bewegt werden.
Weil mir gestern [...]]]></description>
			<content:encoded><![CDATA[<p>Wer sich an Spiele wie &#8220;Shadow of the Beast&#8221; erinnert, der muss sich auch zwangsweise an diesen netten Pseudo-3D Effekt erinnern, mit dem diese Spiele ihren coolen Look erhielten. Parallax Scrolling nennt man diese Technik übrigens, bei der verschiedene Layer aus Grafiken übereinander gelegt und unterschiedlich schnell horizontal oder auch vertikal bewegt werden.</p>
<p>Weil mir gestern Abend langweilig war, habe ich mich damit beschäftigt den Parallax Effekt versuchsweise in JavaScript umzusetzen. Als Bibliotheken verwende ich dabei PrototypeJS und Scriptaculous. Nachdem ich mit einem Grafikprogramm meine 3 Layer gezeichnet und PNGs mit Transparenz exportiert hatte, ging es an die Umsetzung. Schnell wurde mir klar, wie simpel es im Grunde ist mit ein wenig CSS und JavaScript diesen Effekt zu erzeugen.<span id="more-325"></span></p>
<p>Das HTML Grundgerüst besteht lediglich aus 3 DIV Layern:</p>
<pre class="brush:html">
&lt;div id=&quot;layer_bg&quot;&gt;
	&lt;div id=&quot;layer2&quot;&gt;
		&lt;div id=&quot;layer1&quot;&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;
</pre>
<p>Auf diese DIVs werden ein paar einfache CSS Regeln angewendet, um die Hintergrundgrafiken zu setzen. Zudem wird noch die Breite und Höhe definiert und der &#8220;overflow&#8221; auf &#8220;hidden&#8221; gesetzt. So wird es möglich per CSS Anweisung &#8220;background-position&#8221; den Hintergrund, also unseren Parallax-Layer, zu verschieben und einen Scroll-Effekt zu realisieren.</p>
<pre class="brush:css">
#layer_bg {
	border:10px solid #FFF;
	width:1150px;
	height:400px;
	margin:auto auto;
	background-image:url( 'layer_bg.png' );
	background-repeat:repeat-x;
	background-position:0px 0px;
	overflow:hidden;
}
#layer1 {
	background-image:url( 'layer1.png' );
	background-repeat:repeat-x;
	background-position:0px 0px;
	width:1150px;
	height:400px;
	overflow:hidden;
}
#layer2 {
	background-image:url( 'layer2.png' );
	background-repeat:repeat-x;
	background-position:0px 0px;
	width:1150px;
	height:400px;
	overflow:hidden;
}
</pre>
<p>Die Bewegung der Hintergrundgrafiken übernimmt eine kleine JavaScript-Funktion, an welche die Art der Bewegung übergeben wird.</p>
<pre class="brush:js">
var position_index1 = 0;
var position_index2 = 0;
var position_index3 = 0;
var effect_running = false;
function run_effect( $move_type )
{
	if( !effect_running )
	{
		effect_running = true;
		if( $move_type == 'move_left' )
		{
			position_index3 += 200;
			position_index2 += 200;
			position_index1 += 200;
		}
		if( $move_type == 'move_right' )
		{
			position_index1 -= 200;
			position_index2 -= 200;
			position_index3 -= 200;
		}
		if( $move_type == 'rotate_left' )
		{
			position_index3 += 200;
			position_index2 += 50;
			position_index1 -= 200;
		}
		if( $move_type == 'rotate_right' )
		{
			position_index3 -= 200;
			position_index2 -= 50;
			position_index1 += 200;
		}
		new Effect.Morph( 'layer_bg', { style:'background-position:' + (position_index3 * 1) + 'px 0px;' } );
		new Effect.Morph( 'layer2', { style:'background-position:' + (position_index2 * 2) + 'px 0px;' } );
		new Effect.Morph( 'layer1', { style:'background-position:' + (position_index1 * 3) + 'px 0px;', afterFinish:function() { effect_running = false; } } );
	}
}
</pre>
<p>Bei Eintritt in die Funktion wir zuerst geprüft, ob eine Bewegung nicht bereits läuft, falls das nicht der Fall ist, werden für die unterschiedlichen Bewegungs-Arten die neuen Werte für die Hintergrund-Position des Hintergrundbildes berechnet und anschließend mit dem Effekt &#8220;Morph&#8221; gesetzt. Je näher der Layer an der &#8220;Kamera&#8221; ist, um so mehr (schneller) wird er bewegt, wodurch dem Betrachter eine dritte Dimension vorgegaukelt wird.</p>
<p>Wer das <strong><a href="http://www.codemonster.de/parallax/">vollendete Versuchsobjekt betrachten</a></strong> möchte, der kann das nun gerne tun und noch einen Blick in den Quellcode der Seite werfen. Ich habe den Code noch um einige Kleinigkeiten erweitert, z.B. um die Steuerung per Pfeiltasten.</p>
<p>Natürlich ist das mal wieder sinnloses eyecandy, denkbar wäre aber, ein schickes Menü damit zu realisieren.</p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/parallax-scrolling-effekt-mit-prototypescriptaculous-javascript/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SOAP Dienste programmieren mit PHP</title>
		<link>http://thegeek.de/soap-dienste-programmieren-mit-php</link>
		<comments>http://thegeek.de/soap-dienste-programmieren-mit-php#comments</comments>
		<pubDate>Tue, 10 Nov 2009 13:28:11 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[soap]]></category>
		<category><![CDATA[web-service]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=323</guid>
		<description><![CDATA[Wer für seine eigene Anwendung eine Web-API anbieten möchte, hat vielfältige Möglichkeiten dies zu realisieren. Per einfachem HTTP GET oder POST Request und einer Rückgabe als XML/RSS/CSV/JSON/whatever, oder &#8211; was ich etwas eleganter finde &#8211; per SOAP. Dabei ist das Entwickeln eines eigenen SOAP Dienstes mit PHP gar nicht so kompliziert, wie vielleicht vermutet. Zumindest [...]]]></description>
			<content:encoded><![CDATA[<p>Wer für seine eigene Anwendung eine Web-API anbieten möchte, hat vielfältige Möglichkeiten dies zu realisieren. Per einfachem HTTP GET oder POST Request und einer Rückgabe als XML/RSS/CSV/JSON/whatever, oder &#8211; was ich etwas eleganter finde &#8211; per SOAP. Dabei ist das Entwickeln eines eigenen SOAP Dienstes mit PHP gar nicht so kompliziert, wie vielleicht vermutet. Zumindest finde ich SOAP schöner als die weitere Alternative XML-RPC.<span id="more-323"></span></p>
<p>Aber nun zur Definition von SOAP (Quelle: Wikipedia): SOAP (ursprünglich für Simple Object Access Protocol) ist ein Netzwerkprotokoll, mit dessen Hilfe Daten zwischen Systemen ausgetauscht und Remote Procedure Calls durchgeführt werden können. SOAP stützt sich auf andere Standards: XML zur Repräsentation der Daten und Internet-Protokolle der Transport- und Anwendungsschicht (vgl. TCP/IP-Referenzmodell) zur Übertragung der Nachrichten. Die gängigste Kombination ist SOAP über HTTP und TCP.</p>
<p>In der Praxis bedeutet das folgendes: In einer XML Datei (WSDL) werden Nachrichten-Typen definiert und an Operationen gebunden. Dabei gibt es Input-Nachrichten und Output-Nachrichten, sprich Übergaben und Rückgaben. Die WSDL Datei (WSDL = Web Services Description Language) wird dabei vom Client, als auch vom Server genutzt und regelt so die Kommunikation dieser beider Stellen.</p>
<p>Die Vorgehensweise um einen neuen Web-Service zu erstellen ist bei mir immer zuerst die WSDL zu erzeugen, danach die Operationen im Server abzubilden, um diese anschließend mit dem Client zu testen. Eine Beispiel WSDL könnte z.B. so aussehen:</p>
<pre class="brush:xml">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;definitions name=&quot;TheGeek&quot;
	targetNamespace=&quot;http://thegeek.de/wp-soap/thegeek.wsdl&quot;
	xmlns:tns=&quot;http://thegeek.de/wp-soap/thegeek.wsdl&quot;
	xmlns=&quot;http://schemas.xmlsoap.org/wsdl/&quot;
	xmlns:soap=&quot;http://schemas.xmlsoap.org/wsdl/soap/&quot;
	xmlns:xsd=&quot;http://www.w3.org/2001/XMLSchema&quot;&gt;

	&lt;!-- GET LATEST POSTS --&gt;
	&lt;message name=&quot;RequestGetPostsIn&quot;&gt;
		&lt;part name=&quot;apikey&quot; type=&quot;xsd:string&quot;/&gt;
		&lt;part name=&quot;num&quot; type=&quot;xsd:integer&quot;/&gt;
	&lt;/message&gt;
	&lt;message name=&quot;RequestGetPostsOut&quot;&gt;
		&lt;part name=&quot;returncode&quot; type=&quot;xsd:integer&quot;/&gt;
		&lt;part name=&quot;error&quot; type=&quot;xsd:string&quot;/&gt;
		&lt;part name=&quot;posts&quot; type=&quot;xsd:struct&quot;/&gt;
		&lt;part name=&quot;posts_count&quot; type=&quot;xsd:integer&quot;/&gt;
	&lt;/message&gt;
	&lt;portType name=&quot;RequestGetPosts_PortType&quot;&gt;
		&lt;operation name=&quot;GetPosts&quot;&gt;
			&lt;input message=&quot;tns:RequestGetPostsIn&quot;/&gt;
			&lt;output message=&quot;tns:RequestGetPostsOut&quot;/&gt;
		&lt;/operation&gt;
	&lt;/portType&gt;
	&lt;binding name=&quot;GetPosts_Binding&quot; type=&quot;tns:RequestGetPosts_PortType&quot;&gt;
		&lt;soap:binding style=&quot;rpc&quot; transport=&quot;http://schemas.xmlsoap.org/soap/http&quot;/&gt;
		&lt;operation name=&quot;GetPosts&quot;&gt;
			&lt;soap:operation soapAction=&quot;GetPosts&quot;/&gt;
			&lt;input&gt;
				&lt;soap:body
					encodingStyle=&quot;http://schemas.xmlsoap.org/soap/encoding/&quot;
					namespace=&quot;urn:thegeek-getpostsservice&quot;
					use=&quot;encoded&quot;/&gt;
			&lt;/input&gt;
			&lt;output&gt;
				&lt;soap:body
					encodingStyle=&quot;http://schemas.xmlsoap.org/soap/encoding/&quot;
					namespace=&quot;urn:thegeek-getpostsservice&quot;
					use=&quot;encoded&quot;/&gt;
			&lt;/output&gt;
		&lt;/operation&gt;
	&lt;/binding&gt;
	&lt;service name=&quot;GetPosts_Service&quot;&gt;
		&lt;documentation&gt;Return latest posts&lt;/documentation&gt;
		&lt;port binding=&quot;tns:GetPosts_Binding&quot; name=&quot;GetPosts_Port&quot;&gt;
			&lt;soap:address location=&quot;http://thegeek.de/wp-soap/index.php&quot;/&gt;
		&lt;/port&gt;
	&lt;/service&gt;

&lt;/definitions&gt;
</pre>
<p>Diese WSDL definiert eine einfache Funktion &#8220;GetPosts&#8221; mit einer eingehenden Nachricht und einer ausgehenden Nachricht. Für die einzelnen Felder der Nachrichten sind entsprechende Typen definiert. Nachdem die Nachrichten an die Operation &#8220;GetPosts&#8221; gebunden wurden, wird mit dieser Operation ein Soap-Service definiert. Ein Service besteht also aus einem Binding, welches wiederum aus eine Input- und/oder Output-Message besteht. Das klingt nun zugegeben ziemlich kompliziert, ist aber in der Praxis wirklich einfach nachzuvollziehen, wenn wir uns mal den Server-Quellcode zu dieser WSDL Definition ansehen.</p>
<pre class="brush:php">
&lt;?php

// SOAP config array
$soap_config = array( 'encoding' =&gt; 'UTF-8' );

// Don't cache WSDL files, mandatory for development
ini_set( 'soap.wsdl_cache_enabled', '0' );

class thegeek_soapserver
{
	function __construct( $parameters )
	{

	}

	public function GetPosts( $apikey = '', $num = 10 )
	{
		if( $apikey == 'demoapikey' )
		{
			$posts = array( 	array( 'title' =&gt; 'Demo Post 1', 'body' =&gt; 'Demo content 1' ),
						array( 'title' =&gt; 'Demo Post 2', 'body' =&gt; 'Demo content 2' ),
						array( 'title' =&gt; 'Demo Post 3', 'body' =&gt; 'Demo content 3' ),
						array( 'title' =&gt; 'Demo Post 4', 'body' =&gt; 'Demo content 4' )
			);
			return array(	'return' =&gt; true,
					'error' =&gt; '',
					'posts' =&gt; $posts,
					'posts_count' =&gt; 0
			);
		}
		// API KEY FAIL
		else
		{
			return array(	'return' =&gt; false,
					'error' =&gt; 'API KEY INVALID',
					'posts' =&gt; array(),
					'posts_count' =&gt; 0
			);
		}
	}
}

// Run SOAP server
$soapserver = new SoapServer( 'http://thegeek.de/wp-soap/thegeek.wsdl', $soap_config );
$soapserver -&gt; setClass( 'thegeek_soapserver', 'some parameters for the constructor (example only...)' );
$soapserver -&gt; handle();

?&gt;
</pre>
<p>Nachdem die Soap-Config für die PHP Klasse &#8220;SoapServer&#8221; definiert und das caching von WSDL Dateien per &#8220;ini_set&#8221; ausgeschaltet wurde, folgt unsere eigene Klasse, die den Web-Service abbildet. Der Konstruktor kann wie gewohnt definiert werden, auch beim Initialisieren unserer Klasse über die PHP Klasse &#8220;SoapServer&#8221;, können beliebige Parameter übergeben werden. Übrigens sind auch extends problemlos möglich.</p>
<p>Dann findet sich in der Klasse eine Methode, welche unseren SoapService &#8220;GetPosts&#8221; abbildet, als Übergabeparameter sind die Variablen unserer Input-Nachricht angegeben. Wie die Variablennamen in der Methode gewählt werden ist egal, aber die Methode muss genau so heißen, wie in der WSDL angegeben (soap:operation soapAction=&#8221;GetPosts&#8221;). Der Code in der Methode dient natürlich nur der Verdeutlichung, wie Rückgaben erfolgen, nämlich als assoziatives Array, welches die in der WSDL definierte Output-Nachricht abbildet.</p>
<p>Um unsere Server-Klasse dann zu initialisieren, wird die PHP Klasse &#8220;SoapServer&#8221; mit entsprechenden Parametern (Web-Pfad zur WSDL, SoapConfig) aufgerufen. Danach wird mit Hilfe der Methode &#8220;setClass&#8221; unsere Klasse als Handler ausgewählt und der Server letztendlich mit der Methode &#8220;handle&#8221; konstruiert.</p>
<p>Fehlt eigentlich nur noch ein kleiner Test-Client:</p>
<pre class="brush:php">
&lt;?php

// Create new SOAP client
$soap_client = new SoapClient( 'http://thegeek.de/wp-soap/thegeek.wsdl', array( 'encoding' =&gt; 'UTF-8' ) );
if( is_object( $soap_client ) )
{
	$soap_result = $soap_client -&gt; GetPosts( 'demoapikey', 10 );
	// Debug output
	echo &quot;&lt;pre&gt;&quot;;
	print_r( $soap_result );
	echo &quot;&lt;/pre&gt;&quot;;
}
else	die( 'SOAP Server not available' );

?&gt;
</pre>
<p>Der Client ist ziemlich problemlos umzusetzen: Einfach mit der PHP Klasse &#8220;SoapClient&#8221; ein Client-Objekt erzeugen (Web-Pfad zur WSDL übergeben) und die Methoden (= Operationen) wie in der WSDL definiert nutzen. Obiges Beispiel gibt folgendes aus:</p>
<pre class="brush:plain">
Array
(
    [returncode] =&gt;
    [error] =&gt;
    [posts] =&gt; Array
        (
            [0] =&gt; Array
                (
                    [title] =&gt; Demo Post 1
                    [body] =&gt; Demo content 1
                )

            [1] =&gt; Array
                (
                    [title] =&gt; Demo Post 2
                    [body] =&gt; Demo content 2
                )

            [2] =&gt; Array
                (
                    [title] =&gt; Demo Post 3
                    [body] =&gt; Demo content 3
                )

            [3] =&gt; Array
                (
                    [title] =&gt; Demo Post 4
                    [body] =&gt; Demo content 4
                )

        )

    [posts_count] =&gt; 0
)
</pre>
<p>So schwierig ist das mit SOAP und PHP also nicht. Wichtig ist allerdings noch: PHP muss mit der Option &#8220;&#8211;enable-soap&#8221; kompiliert werden, um die SOAP Extension nutzen zu können. Alternativ kann aber auch das SOAP PEAR Paket genutzt oder auf die Klasse nuSoap zurückgegriffen werden.</p>
<p>Wer selbst mal von seinem Webspace aus testen will: <a href="http://thegeek.de/wp-soap/thegeek.wsdl">http://thegeek.de/wp-soap/thegeek.wsdl</a></p>
<p>Wer Fragen hat: Comments are open.</p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/soap-dienste-programmieren-mit-php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Twitter Listen als RSS/Atom Feed abonnieren</title>
		<link>http://thegeek.de/twitter-listen-als-rssatom-feed-abonnieren</link>
		<comments>http://thegeek.de/twitter-listen-als-rssatom-feed-abonnieren#comments</comments>
		<pubDate>Mon, 09 Nov 2009 12:17:53 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[atom]]></category>
		<category><![CDATA[listen]]></category>
		<category><![CDATA[rss]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=317</guid>
		<description><![CDATA[Die neue Listenfunktion bei Twitter ist klasse, denn damit lassen sich endlich die Leute denen man folgt thematisch gruppieren. Da die Listen nun auch per Twitter API angesprochen werden können, ist es möglich die Tweets einer Liste per RSS bzw. Atom zu abonnieren. Eine praktische Sache.
Einfach im Browser oder RSS Reader eine dem folgenden Format [...]]]></description>
			<content:encoded><![CDATA[<p>Die neue Listenfunktion bei Twitter ist klasse, denn damit lassen sich endlich die Leute denen man folgt thematisch gruppieren. Da die Listen nun auch per Twitter API angesprochen werden können, ist es möglich die Tweets einer Liste per RSS bzw. Atom zu abonnieren. Eine praktische Sache.</p>
<p>Einfach im Browser oder RSS Reader eine dem folgenden Format entsprechende URL eingeben:</p>
<p><strong>http://api.twitter.com/1/ACCOUTNAME/lists/LISTENNAME/statuses.atom</strong></p>
<p>Wobei &#8220;<strong>ACCOUNTNAME</strong>&#8221; durch den Twitternamen z.B. &#8220;motorradblogger&#8221; zu ersetzen ist. Das gleiche gilt natürlich für &#8220;<strong>LISTENNAME</strong>&#8220;.</p>
<p>Zum Beispiel so: <a href="http://api.twitter.com/1/motorradblogger/lists/motorradblogger/statuses.atom">Meine Liste von Motorradbloggern</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/twitter-listen-als-rssatom-feed-abonnieren/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>E-Mail Adresse vor Spam-Robots schützen</title>
		<link>http://thegeek.de/e-mail-adresse-vor-spam-robots-schutzen</link>
		<comments>http://thegeek.de/e-mail-adresse-vor-spam-robots-schutzen#comments</comments>
		<pubDate>Tue, 03 Nov 2009 12:16:39 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[spam]]></category>

		<guid isPermaLink="false">http://thegeek.de/e-mail-adresse-vor-spam-robots-schutzen</guid>
		<description><![CDATA[Wenn man mal eben fix eine E-Mail Adresse vor Spam-Robots sichern will, dann geht das ganz einfach mit ein wenig JavaScript.

	// Entweder so
	document.write( '&#60;a h'+'ref="ma'+'ilto'+':post'+'@'+'thegeek'+'.'+'de"&#62;post'+'@'+'thegeek'+'.'+'de&#60;/a&#62;' );

	// Oder auch so [prototype]
	$('my_mail_adress').update( '&#60;a h'+'ref="ma'+'ilto'+':post'+'@'+'thegeek'+'.'+'de"&#62;post'+'@'+'thegeek'+'.'+'de&#60;/a&#62;' );

Wichtig ist noch folgendes:

	&#60;noscript&#62;
		post AT thegeek . de
	&#60;/noscript&#62;

Sollte JavaScript nicht verfügbar sein, wird einfach die E-Mail Adresse ohne &#8220;@&#8221;-Zeichen und Domain ausgegeben, was [...]]]></description>
			<content:encoded><![CDATA[<p>Wenn man mal eben fix eine E-Mail Adresse vor Spam-Robots sichern will, dann geht das ganz einfach mit ein wenig JavaScript.</p>
<pre class="brush:js">
	// Entweder so
	document.write( '&lt;a h'+'ref="ma'+'ilto'+':post'+'@'+'thegeek'+'.'+'de"&gt;post'+'@'+'thegeek'+'.'+'de&lt;/a&gt;' );

	// Oder auch so [prototype]
	$('my_mail_adress').update( '&lt;a h'+'ref="ma'+'ilto'+':post'+'@'+'thegeek'+'.'+'de"&gt;post'+'@'+'thegeek'+'.'+'de&lt;/a&gt;' );
</pre>
<p>Wichtig ist noch folgendes:</p>
<pre class="brush:html">
	&lt;noscript&gt;
		post AT thegeek . de
	&lt;/noscript&gt;
</pre>
<p>Sollte JavaScript nicht verfügbar sein, wird einfach die E-Mail Adresse ohne &#8220;@&#8221;-Zeichen und Domain ausgegeben, was die Spam-Robots nicht dekodieren können.</p>
<p>Siehe hier (mit Protype umgesetzt, da document.write bei asynchron geladenem Content nicht sinnvoll ist):
<div id="my_mail_adress"></div>
<p><script type="text/javascript">
// <!--
	$('my_mail_adress').update( '<a h'+'ref="ma'+'ilto'+':post'+'@'+'thegeek'+'.'+'de">post'+'@'+'thegeek'+'.'+'de</a>' );
// -->
</script></p>
<p>PS: Die Mail-Adresse existiert nicht und wurde wirklich dynamisch mit JavaScript eingefügt. :-)</p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/e-mail-adresse-vor-spam-robots-schutzen/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
