<?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>Thu, 26 Jan 2012 13:19:21 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Ein Select Auswahlfeld mit Prototype elegant filtern &#8211; ohne Ajax.Request</title>
		<link>http://thegeek.de/ein-select-auswahlfeld-mit-prototype-elegant-filtern-ohne-ajax-request</link>
		<comments>http://thegeek.de/ein-select-auswahlfeld-mit-prototype-elegant-filtern-ohne-ajax-request#comments</comments>
		<pubDate>Fri, 23 Dec 2011 12:59:52 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[filter]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[prototype]]></category>
		<category><![CDATA[select]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=641</guid>
		<description><![CDATA[Wer kennt das Problem als Programmierer nicht? Die User meckern, bei ewig vielen Optionen in einem Auswahlfeld &#8211; und das zurecht! Nun können die Optionen des Auswahlfelds mittels Ajax.Request und einem Suchfeld gefiltert werden, aber ein Request ist eben ein Request und ich habe mir deswegen etwas überlegt, was ohne Request auskommt. Dabei herausgekommen ist [...]]]></description>
			<content:encoded><![CDATA[<p>Wer kennt das Problem als Programmierer nicht? Die User meckern, bei ewig vielen Optionen in einem Auswahlfeld &#8211; und das zurecht! Nun können die Optionen des Auswahlfelds mittels Ajax.Request und einem Suchfeld gefiltert werden, aber ein Request ist eben ein Request und ich habe mir deswegen etwas überlegt, was ohne Request auskommt. Dabei herausgekommen ist eine kleine JavaScript-Funktion, die ich gerne zur Verfügung stelle.</p>
<p>Aber zuerst eine kleines Beispiel, wie der HTML-Code dazu aussehen könnte:</p>
<pre class="brush:html">&lt;select name="auswahl" id="auswahl"&gt;
	&lt;option value=""&gt;--Bitte wählen --&lt;/option&gt;
	&lt;option value="1"&gt;Eins&lt;/option&gt;
	&lt;option value="2"&gt;Eins&lt;/option&gt;
	&lt;option value="3"&gt;Eins&lt;/option&gt;
	&lt;option value="4"&gt;Eins&lt;/option&gt;
	&lt;option value="5"&gt;Eins&lt;/option&gt;
	&lt;option value="1000000"&gt;Einemiooooon!!!!&lt;/option&gt;
&lt;/select&gt;

Filtern:
&lt;input type="text" size="12" value="" onkeyup="filterSelectField( 'auswahl', this.value )"/&gt;</pre>
<p>Die dazugehörige JavaScript-Funktion sieht dann so aus:</p>
<pre class="brush:javascript">function filterSelectField( fieldid, s ) {
	var rex = new RegExp( '^' + s.replace( '\.', '\\.' ), "i" );
	$$('select#' + fieldid + ' option').each( function (ele) {
		if( ele.value != '' )
		{
			if( ele.innerHTML.search( rex ) == -1  )
				ele.hide();
			else
				ele.show();
		}
	} );
}</pre>
<p>Die Funktionsweise ist schnell erklärt: Mittels einer RegEx wird die Bennenung des Werts der &#8220;option&#8221; durchsucht und bei einem Treffer angezeigt und bei keinem Treffer ausgeblendet. Einfacher und schneller geht&#8217;s nun wirklich nicht. :-)</p>
<p>Viel Spaß damit.</p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/ein-select-auswahlfeld-mit-prototype-elegant-filtern-ohne-ajax-request/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Anonymous entwickelt &#8220;RefRef&#8221; als Nachfolger von &#8220;LOIC&#8221; &#8211; viele Fragen bleiben offen</title>
		<link>http://thegeek.de/anonymous-entwickelt-refref-als-nachfolger-von-loic-viele-fragen-bleiben-offen</link>
		<comments>http://thegeek.de/anonymous-entwickelt-refref-als-nachfolger-von-loic-viele-fragen-bleiben-offen#comments</comments>
		<pubDate>Fri, 26 Aug 2011 15:43:22 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Coding]]></category>
		<category><![CDATA[anonymous]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[loic]]></category>
		<category><![CDATA[refref]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=595</guid>
		<description><![CDATA[Derzeit ist die Hacker Gruppierung Anonymous des öfteren in Medien, sei es mit dem bereits jetzt legendärem Hack der Gema durch die AnonyPwnies, oder mit der &#8220;Operation Bart&#8221; in den USA. Zudem läuft hier in Deutschland derzeit die &#8220;Operation Summerstorm&#8221;, sowie &#8220;Operation Blitzkrieg&#8221;, die sich den Rechtsradikalen entgegenstellt und deren Webseiten hackt und mit DDoS [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_596" class="wp-caption alignleft" style="width: 225px"><img class="size-full wp-image-596" title="Anonymous" src="http://thegeek.de/wp-content/uploads/2011/08/anon.jpg" alt="Anonymous" width="215" height="250" /><p class="wp-caption-text">Anonymous</p></div>
<p>Derzeit ist die Hacker Gruppierung Anonymous des öfteren in Medien, sei es mit dem bereits jetzt legendärem Hack der Gema durch die <a href="https://twitter.com/#%21/AnonyPwnies">AnonyPwnies</a>, oder mit der &#8220;Operation Bart&#8221; in den USA. Zudem läuft hier in Deutschland derzeit die &#8220;Operation Summerstorm&#8221;, sowie &#8220;Operation Blitzkrieg&#8221;, die sich den Rechtsradikalen entgegenstellt und deren Webseiten hackt und mit DDoS Angriffen blockiert &#8211; so zum Beispiel die Webseite der NPD. Bei den DDoS Angriffen wird das Tool LOIC (&#8220;Large Orbit Ion Canon&#8221;) eingesetzt, was allerdings so einige Probleme mit sich bringt: Die Server werden von vielen Teilnehmern der Aktionen mit sinnlosen HTTP Requests geflutet, die IP Adressen der Teilnehmer landen dabei natürlich im Log des Webservers, wodurch es in den .NL und in .GB bereits zu Festnahmen gekommen ist, die IP Adressen führten die Ermittler zu den Angreifern. Die IP ließe sich natürlich auch fälschen, doch die Mehrheit der Teilnehmer an den DDoS Aktionen wird wohl ein Windows XP/Vista/7 verwenden, wo IP Spoofing nicht mehr möglich ist. Um diese Problematik zu umgehen, entwickeln einige Anonymous Hackavisten derzeit an einem neuen Tool mit dem Namen &#8220;RefRef&#8221;, das nach einem anderen Prinzip arbeitet. Ich habe mir das Thema angesehen und will nun ein wenig etwas darüber schreiben. <span id="more-595"></span></p>
<p>Laut den Entwickeln wird das in JavaScript geschriebene Tool RefRef darauf basieren, <a href="http://www.gulli.com/news/16774-anonymous-entwickelt-neues-angriffswerkzeug-2011-08-04">dass sich per JavaScript</a> &#8220;die eigene Rechenkapazität der Website gegen [die Website] selbst richtet&#8221;. Dazu nutzt das Tool &#8220;Schwachstellen in SQL aus, um einen vernichtenden Effekt auf die Ziel-Website auszuüben&#8221;. Laut Informationen der Entwickler nutze RefRef eine Schwachstelle im Javascript und im SQL-Server aus, um eine JavaScript Datei im Temp-Verzeichnis des Servers abzulegen, um mit einem erneuten Request diesen in eine Endlosschleife von Selbstaufrufen zu bringen. Das klingt für mich ehrlich gesagt ziemlich seltsam und verworren, gut war glaube ich auch ein Artikel beim &#8220;ehemaligen Nachrichtenmagazin&#8221;. Auch die weiteren Medienberichte zum neuen Tool geben wenig Aufschluss, sind alle irgendwie unterschiedlich und ich halte die Aussagen für ziemliches Snakeoil &#8211; trotz der Tatsache, das dieses neue Tool angeblich bereits erfolgreich <a href="http://1.bp.blogspot.com/-B71MTncg6d4/Tjgly4MdH1I/AAAAAAAAAaU/AlIHtfrZLBE/s1600/Untitled-2.jpg">an pastebin</a> getestet wurde.</p>
<p>Was ich mir vorstellen könnte, wäre allerdings folgendes Szenario: Wenn eine Seite für SQL-Injections anfällig ist, wäre es durchaus möglich von außen nicht erwünschte Inhalte in die Seite einzuschleusen. Dieser Inhalt könnte z.B. ein kleines JavaScript sein, dass in einem sehr kleinen Intervall asynchrone HTTP Requests erzeugt, die ebenfalls die SQL-Injection ausnutzen und den Datenbank Server zusätzlich mit sinnlosem Quatsch (z.B. &#8220;BENCHMARK&#8221; hehe) beschäftigen. Hierdurch würden auch reguläre Besucher der Seite zum DDoS beitragen, was ein unglaublich wirkungsvoller Multiplikator, gerade bei stark frequentierten Seiten wäre. Zudem handelt es sich bei einem solchen Angriff um einen Doppelschlag: Die Datenbank wird in die Knie gezwungen und auch der Webserver wird ordentlich beschäftigt. Zur Verfolgbarkeit: Würde die SQL-Injection z.B. über TOR oder I2P gemacht, wäre der Angreifer nicht durch Ermittlungsbehörden aufspürbar. Und ein Anonymisierungsdienst bietet sich an, weil es ja kein DDoS Angriff ist, zu dem ein Netz von Bots oder Personen benötigt wird. Lediglich ein Request für den Inject, das war es.</p>
<p>Problem bei der ganzen Sache: Nicht alle Webauftritte sind anfällig für SQL-Injections. Es muss also eine gravierende Lücke in der Software vorhanden sein, so dass ein externer Zugriff auf die Datenbank ermöglicht wird, aber es ist ein denkbares Szenario und wie die AnonyPwnies beim GEMA Hack sagten &#8220;as always startet with a sql injection&#8221;. Die Entwickler schreiben dazu folgendes:</p>
<blockquote><p>&#8220;RefRef is a revolutionary DoS java site. Basically, by using an SQL and .js vulnerability, you can send a page request packet from your home computer with embedded .js file, because of the vulnerability in the SQL/Javascript engine on MOST websites, the site actually TEMPs the .js file on its own server. So now the .js is in place on the host of the site. Next since you still have the request, it picks up the .js file, and all of the requesting for packets power happens on the server, not the requestee. I send two packets from my iphone, and everything else happens on the server. Basically eats itself apart, because since both are on the server, its all a local connection. This tool only makes you vulnerable if you don’t keep your systems patched, perform the basic security, which is how Sony got caught with it’s pants down.&#8221;</p></blockquote>
<p>Ich verstehe diese Aussage nicht wirklich, weil ich auf anhieb keine Warnung gefunden habe, dass für Apache so ein Angriffsvektor besteht.  Sie sprechen von zwei Requests, der erste ein manipulierter HTTP Request, der eine JavaScript Datei im tmp Verzeichnis ablegt, und den zweiten, der die Datei aufnimmt und ab da sollen alle Requests lokal laufen. In anderen Berichten steht dann überhaupt nichts mehr von einer JavaScript Datei, sondern nur, dass das Tool in JavaScript entwickelt würde. Es ist daher auch nicht auszuschließen, dass da einfach falsch zitiert wurde, oder ähnliches, denn <a href="http://www.hackingtricks.in/2011/07/refref-ddos-tool-developed-by-anonymous.html">folgender Text von hackingtricks.in</a> lässt eher auf einen HTTP Header Exploit schließen, obwohl der erste Satz des oben zitierten Textes, doch eher nach der SQL Injection Variante klingt.</p>
<blockquote><p>&#8220;Wie sich herausstellt, wird der Angriff clientseitig gestarted und sendet ein separates Skript mit dem Verbindungs-Request zum Zielserver. Dieser Request ist tatsächlich der Exploit selbst und sobald der Server beginnt den Request zu verarbeiten wird er damit fortfahren, bis er abstürzt. Kurz gesagt, je stärker der Server um so schneller wird er abstürzen.&#8221;</p></blockquote>
<div id="attachment_597" class="wp-caption alignright" style="width: 310px"><a title="Screenshot von RefRef posted by Anonymous" href="http://thegeek.de/wp-content/uploads/2011/08/refref.jpg" rel="lightbox"><img class="size-thumbnail wp-image-597  " title="Screenshot von RefRef" src="http://thegeek.de/wp-content/uploads/2011/08/refref-300x300.jpg" alt="Screenshot von RefRef" width="300" height="300" /></a><p class="wp-caption-text">Screenshot von RefRef</p></div>
<p>Generell sind die Informationen der ausländischen Medien andere, als das was deutsche Medien &#8211; unter anderem auch Gulli.com &#8211; zur RefRef geschrieben haben. Ein HTTP Header Angriff hat nämlich wenig mit SQL und JavaScript zu tun. Die Informationslage ist also mehr als unklar. Tja, was ist es denn nun? SQL injected content hack, schnödes DDoS, Webserver Exploit, oder gar alles zusammen? Auch der Screenshot, der von Anonymous im Internet gepostet wurde trägt nicht wirklich zur Klärung bei. Das sieht nämlich nach einem ziemlich einfachen JavaScript DDoS Tool aus, was keinen Unterschied zu LOIC darstellen würde. Eine weitere Option wäre allerdings noch, dass es eine Kombination aus DDoS und SQL Injection ist. Der Server würde dann von Hand bombardiert, wobei die SQL Injections vom Tool angehangen werden, um den Datenbank-Server lahmzulegen.</p>
<p>Ich persönlich vermute aber, dass es sich um ein Tool für das oben von mir beschriebe Szenario handelt. SQL Injection, JavaScript wird in die Ausgabe eingeschmuggelt und die Besucher bombardieren unwissentlich Server und Datenbank. Eigentlich recht elegant, aber dazu muss die Seite eben anfällig für SQL Injections sein. Wir werden es im September sehen, dann soll das Tool angeblich released werden.</p>
<p>Ich bin gespannt und hoffe, dass sich das ganze nicht wirklich als Snakeoil, oder einfach nur eine witzige Aktion von Anon handelt, denn rein sicherheitstechnisch wäre es interessant den Angriff zu untersuchen, damit wir unsere Server dagegen absichern können.</p>
<p>Wenn jemand Tipps, Anregungen, einen Link hat, oder einfach mehr weiß als ich, dann schreibt doch bitte einen Kommentar. :-)</p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/anonymous-entwickelt-refref-als-nachfolger-von-loic-viele-fragen-bleiben-offen/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pornöse JavaScript GUIs, die doch barrierefrei sind</title>
		<link>http://thegeek.de/pornose-javascript-guis-die-doch-barrierefrei-sind</link>
		<comments>http://thegeek.de/pornose-javascript-guis-die-doch-barrierefrei-sind#comments</comments>
		<pubDate>Fri, 14 Jan 2011 12:28:58 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Coding]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[barrierefrei]]></category>
		<category><![CDATA[gui]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=527</guid>
		<description><![CDATA[Mit Prototype, Scriptaculous, jQuery und Konsorten lassen sich wunderbare Interfaces zaubern, herrlich interaktiv mit tollen Effekten und vorallem wesentlich schneller durch den Einsatz von AJAX. Doch wo bleibt dabei die Barrierefreiheit, die ich übrigens im Netz für sehr wichtig halte, nicht nur weil auch blinde Menschen surfen, sondern weil eine barrierefreie Seite automatisch von jedem [...]]]></description>
			<content:encoded><![CDATA[<p>Mit Prototype, Scriptaculous, jQuery und Konsorten lassen sich wunderbare Interfaces zaubern, herrlich interaktiv mit tollen Effekten und vorallem wesentlich schneller durch den Einsatz von AJAX. Doch wo bleibt dabei die Barrierefreiheit, die ich übrigens im Netz für sehr wichtig halte, nicht nur weil auch blinde Menschen surfen, sondern weil eine barrierefreie Seite automatisch von jedem Endgerät besser gelesen werden kann.</p>
<p>JavaScript ist alles andere als barrierefrei, denn die Braille Browser, die von blinden Menschen benutzt werden, beherrschen kein JavaScript. Aber: Wir können trotzdem GUIs mit AJAX und jede Menge Eyecandy programmieren und der shit läuft trotzdem auch ohne JavaScript. Im Grunde ist es sogar kein großer Aufwand und bekanntlich führen sogar mehrere Wege zum Ziel. Den Weg, den ich immer gehe, den möchte ich mal kurz vorstellen. <span id="more-527"></span></p>
<p>Vorweg: Nicht notwendig, aber hilfreich ist der Einsatz eines Template Systems, wie z.B. Smarty. Da ich Smarty aber ziemlich unhandlich finde, habe ich mir seinerzeit mal eine eigene Template-Klasse geschrieben, mir der ich gut zurecht komme.</p>
<p>Erstmal zum grundlegenden Prinzip: Ein AJAX Request wird in der Regel durch eine onclick Aktion oder über das href Attribut eines Links ausgelöst. Soll das Ganze auch ohne JavaScript noch funktionieren muss im href Attribut ein Link stehen, der die Aktion ohne Einsatz eines asynchronen Requests auslöst, im onclick steht der Aufruf des AJAX Requests und danach, ganz wichtig, &#8220;return false&#8221;.</p>
<p>Ein Beispiel für einen solchen Link:</p>
<pre class="brush:html">
&lt;a href="index.php?action=show_entry&#038;entry_id=23" onclick="ajax_request( 'action=show_entry&#038;entry_id=23&#038;ajax=true', 'contentdiv' ); return false;"&gt;Zeige Eintrag&lt;/a&gt;
</pre>
<p>Ist JavaScript beim Klicken des Links nicht aktiv, wird der Link regulär aufgerufen, mit Hilfe von PHP entsprechend ausgewertet und das benötigte HTML erzeugt. Ist JavaScript aktiv, dann wird der AJAX Request gestartet und das reguläre Verfolgen des Links im href Attribut durch &#8220;return false&#8221; unterbunden. An PHP wird mittels Parameter &#8220;ajax=true&#8221; übermittelt, dass nicht das vollständige HTML zu erzeugen ist, sondern nur das was für den Inhaltsbereich benötigt wird.</p>
<p>Das klingt nun erstmal so, als wäre es sehr aufwändig, aber mit einem Template System ist es ein Kinderspiel. Ein wenig PHP Pseudocode dazu:</p>
<pre class="brush:php">
	// Auswahl des Templates
	if( empty( $_REQUEST[ 'ajax' ] ) )
	{
		$content = new template( 'templates/tpl_main.html' );

		$menu = new template( 'templates/tpl_menu.html' );
		$menu -> finish();

		$sidebar = new template( 'template/tpl_sidebar.html' );
		$sidebar -> finish();

		$content -> set( 'menu', $menu -> get_html() );
		$content -> set( 'sidebar', $sidebar -> get_html() );
	}
	else
	{
		$content = new template( 'templates/tpl_ajax.html' );
	}

	// Erzeugen und einsetzen des Inhalts der gewünschten Aktion
	if( $_REQUEST[ 'action' ] == 'show_entry' )
		$content -> set( 'content', show_entry( intval( $_REQUEST[ 'entry_id' ) ) );

	// Template rendern und ausgeben
	$content -> finish();
	echo $content -> get_html();
</pre>
<p>Im Prinzip ist es also ganz einfach: Ist der Parameter &#8220;ajax&#8221; leer, dann wird mittels des Template Systems die vollständige Seite zusammengebaut. Kommt der Request per AJAX, dann wird nur der benötigte Teil ausgegeben und mittels JavaScript in das entsprechende Div gesetzt. Im Prinzip also doch einfacher, als man vermutet.</p>
<p>Auch Formularübergaben können so sehr einfach sowohl per AJAX, als auch regulär abgesendet werden:</p>
<pre class="brush:html">
&lt;form name="entryaddform" id="entryaddform" action="index.php" method="post"&gt;
&lt;input type="hidden" name="action" id="entryaddform_action" value="entry_add"/&gt;
&lt;input type="hidden" name="ajax" id="entryaddform_ajax" value=""/&gt;

&lt;fieldset&gt;
	&lt;legend&gt;Eintrag anlegen&lt;/legend&gt;

	&lt;div&gt;
		&lt;label for="entry_titel"&gt;Bezeichnung des Eintrag&lt;/label&gt;
	&lt;/div&gt;
	&lt;div&gt;
		&lt;input type="text" name="entry_titel" id="entry_titel" size="40"/&gt;
	&lt;/div&gt;

&lt;/fieldset&gt;

&lt;input type="submit" value="Speichern" onclick="$('entryaddform_ajax').value = 'true'; ajax_form( 'entryaddform' ); return false;"/&gt;

&lt;/form&gt;
</pre>
<p>Auch hier ist es wieder sehr einfach: Genau wie beim Link, liegen auf der onclick Aktion des Submit Buttons die entsprechenden JavaScript Anweisungen, um das Hidden Field &#8220;ajax&#8221; mit einem Wert zu füllen, das Formular asynchron abszusenden und um schlussendlich das reguläre Senden des Formulars mit &#8220;return false&#8221; zu unterbinden. Ist JavaScript nicht aktiv, wird das Formular reguläre mit leerem Parameter &#8220;ajax&#8221; abgesendet.</p>
<p>Es ist also tatsächlich relativ einfach eine moderne Webanwendung barrierefrei zu gestalten.</p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/pornose-javascript-guis-die-doch-barrierefrei-sind/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<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 [...]]]></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 [...]]]></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>4</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>
<p><a href="http://flattr.com/thing/331572/Interessantes-Menu-mit-CSS-Rotation" target="_blank"><br />
<img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" /></a></p>
]]></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 [...]]]></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>3</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>
<p><a href="http://flattr.com/thing/331574/WordPress-und-lighttpd-Permalinks-mit-URL-rewriting" target="_blank"><br />
<img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/wordpress-und-lighttpd-permalinks-mit-url-rewriting/feed</wfw:commentRss>
		<slash:comments>2</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 [...]]]></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>
	</channel>
</rss>

