<?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>Der Interaktionsdesigner - PHP, jQuery und CSS &#187; Entwicklung</title>
	<atom:link href="http://www.interaktionsdesigner.de/category/entwicklung/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.interaktionsdesigner.de</link>
	<description>Webentwicklung mit TYPO3, jQuery, CakePHP und Spaß an neuen Projekten</description>
	<lastBuildDate>Wed, 07 Dec 2011 14:26:54 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>Schönes Javascript mit Callbacks</title>
		<link>http://www.interaktionsdesigner.de/2011/12/07/schones-javascript-mit-callbacks/</link>
		<comments>http://www.interaktionsdesigner.de/2011/12/07/schones-javascript-mit-callbacks/#comments</comments>
		<pubDate>Wed, 07 Dec 2011 14:26:29 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=826</guid>
		<description><![CDATA[Callbacks sind jedem jQuery Anweder bekannt. Von bis zu bindet der Webentwickler jede Menge Logik an festgelegte Events. Meiner Meinung nach eine angenehme Art zu programmieren und gut nachvollziehbar, da der Code gut lesbar bleibt, sofern man nicht übertreibt. Wenn man selbst Applikationen programmiert die auf Javascript basieren und später noch diverse Erweiterungen ermöglichen sollen, [...]]]></description>
			<content:encoded><![CDATA[<p>Callbacks sind jedem jQuery Anweder bekannt. Von <code>onClick</code> bis zu <code>onResize</code> bindet der Webentwickler jede Menge Logik an festgelegte Events. Meiner Meinung nach eine angenehme Art zu programmieren und gut nachvollziehbar, da der Code gut lesbar bleibt, sofern man nicht übertreibt.</p>
<p>Wenn man selbst Applikationen programmiert die auf Javascript basieren und später noch diverse Erweiterungen ermöglichen sollen, dann macht es durchaus Sinn eigene Callbacks anzubieten. Sei es in einer jQuery Extension oder einer eigenen Applikation.</p>
<p><span id="more-826"></span></p>
<h2>Die Anforderung</h2>
<p>Zur Erfüllung meiner aktuellen Anforderung habe ich eine Javascript Klasse erstellt die mit dem Operator <code>new</code> erstellt werden kann:</p>
<pre>var myObject = new FunkyObject();</pre>
<p>Perfekt für die erste Anforderung, aber sobald weitere Entwickler involviert werden oder man Teile der Applikation sogar als OpenSource Software veröffentlicht, wäre es ja schön wenn nicht jeder im eigenen Code rum macht sondern ordentlich in seinem Script bleibt:</p>
<pre>var myObject = new FunkyObject({
&nbsp;&nbsp;onLoad: function() {
&nbsp;&nbsp;&nbsp;&nbsp;//do crazy custom things
&nbsp;&nbsp;}
});</pre>
<p>Sieht ordentlich aus und ist ohne Kommentare selbsterklärend: Beim laden werden verrückte Sachen getan. Aber was tut das FunkyObject um die Callbacks aufzurufen?</p>
<h2>Eine Javascript Klasse</h2>
<p>Genau genommen ist eine Javascript Klasse nichts weiter als eine Funktion die sich selbst zurück gibt und über den <code>new</code> Operator erstellt wird. Meine Grundlage sieht so aus:</p>
<pre>var FunkyObject = function(args) {
&nbsp;&nbsp;var defaults = {};
&nbsp;&nbsp;this.args = $.extend(defaults, args);
&nbsp;&nbsp;this.goCrazy();
&nbsp;&nbsp;return this;
};</pre>
<p>Dieser Code setzt jQuery voraus, das die Funktion <code>$.extend</code> mitbringt. Damit wird das übergebene <code>args</code> Objekt durch die in <code>defaults</code> angegebenen Werte aufgefüllt, sofern sie nicht vorhanden sind. Man kann also für das <code>onClick</code> Event ein Standardverhalten hinterlegen:</p>
<pre>var FunkyObject = function(args) {
&nbsp;&nbsp;var defaults = {
&nbsp;&nbsp;onLoad: function() {
&nbsp;&nbsp;&nbsp;&nbsp;//default behavior
&nbsp;&nbsp;};
&nbsp;&nbsp;this.args = $.extend(defaults, args);
&nbsp;&nbsp;this.goCrazy();
&nbsp;&nbsp;return this;
};</pre>
<p>Die Funktion <code>goCrazy()</code> wird ausgeführt sobald die Klasse initialisiert wird. Um dem nächsten Entwickler die Möglichkeit zu geben auch diese Funktion zu überschreiben, werden alle Grundlagen in der <code>prototype</code> Eigenschaft der Klasse definiert:</p>
<pre>var FunkyObject = function(args) { /* ... */ };
FunkyObject.prototype.goCrazy = function() {
&nbsp;&nbsp;// do the init stuff
};</pre>
<p>Mit diesem Konstrukt könnte ein Entwickler im eigenen Script jene Klasse überschreiben ohne in den eigentlichen Quelltext eingreifen zu müssen.</p>
<pre>myObject.goCrazy = function() {
&nbsp;&nbsp;// custom constructor
}</pre>
<p>Das als kleine Anmerkung am Rande, das erklärte Ziel ist der komfortable Aufruf des <code>onLoad</code> Events. Natürlich könnte man über <code>this.args.onClick()</code> einfach die entsprechende Funktion aufrufen, aber sieht das schön aus? Ist das variabel?</p>
<p>Die Antwort lautet nein. </p>
<h2>Schön und variabel</h2>
<p>Viel cooler ist eine total schöne und variable <code>trigger()</code> Funktion zu schreiben, die in den Parametern nach einem Callback sucht und diesen ggf. ausführt.</p>
<pre>FunkyObject.prototype.trigger = function(action) {
&nbsp;&nbsp;var callback = 'on'+this.ucfirst(action);
&nbsp;&nbsp;if(typeof this.args[callback] == 'function') {
&nbsp;&nbsp;&nbsp;&nbsp;this.args[callback]();
&nbsp;&nbsp;};
}</pre>
<p>In der <code>goCrazy</code> Funktion sieht der Aufruf dann so aus:</p>
<pre>var FunkyObject = function(args) { /* ... */ };
FunkyObject.prototype.goCrazy = function() {
&nbsp;&nbsp;this.trigger('load');
};</pre>
<p>Die <code>trigger</code> Funktion baut sich den Eventnamen aus einem <code>on</code> und dem Parameter <code>action</code> zusammen und prüft anschließend ob eine Funktion mit diesem Namen vorhanden ist. Ist dies der Fall wird sie ausgeführt.</p>
<p>Leider gibt es keine Javascript Funktion mit dem Namen <code>ucfirst</code>, aber über die Prototype Eigenschaft kann man das String Objekt entsprechend aufrüsten:</p>
<pre>String.prototype.ucfirst = function() {
&nbsp;&nbsp;return this.substr(0,1).toUpperCase() + this.substr(1,this.length);
};</pre>
<p>Mit diesen zwei Funktionen baut man sich sehr schnell eine Grundlage um variable Scripte zu schreiben die komplett erweitert werden können.</p>
<h2>Parameter für den Callback</h2>
<p>Oft muss der Callback über einen gewissen Zustand informiert werden. Für das benutzte Beispiel könnte es die Information sein ob das Laden erfolgreich war. Bei der Definition des Callbacks muss ein Parameter akzeptiert werden:</p>
<pre>var myObject = new FunkyObject({
&nbsp;&nbsp;onClick: function(success) {
&nbsp;&nbsp;&nbsp;&nbsp;alert(success ? 'hat geklappt!' : 'fehler');
&nbsp;&nbsp;}
});</pre>
<p>Die <code>goCrazy</code> Funktion muss den Status an die <code>trigger</code> Funktion weitergeben:</p>
<pre>FunkyObject.prototype.goCrazy = function() {
&nbsp;&nbsp;success = true;
&nbsp;&nbsp;this.trigger('load', success);
};</pre>
<p>Wir gehen mal von einem grundlegenden Erfolg aus. Das wird es auch sofern die <code>trigger</code> Funktion beigebracht bekommt was sie mit zusätzlichen Parametern anfangen soll:</p>
<pre>FunkyObject.prototype.trigger = function(action) {
&nbsp;&nbsp;var callback = 'on'+this.ucfirst(action);
&nbsp;&nbsp;if(typeof this.args[callback] == 'function') {
&nbsp;&nbsp;&nbsp;&nbsp;this.args[callback](arguments.shift());
&nbsp;&nbsp;};
}</pre>
<p>Viele Änderungen sind es nicht. In der vordefinierten Variable <code>arguments</code> sind sämtliche Parameter vom Aufruf der Funktion gespeichert. Die Array Funktion <code>shift</code> entfernt das erste Element aus dem Array und gibt den Rest zurück. So wird nicht der Callbackname sinnloser Weise an den Callback gegeben sondern alle andere Parameter. So kann man auch mehr als ein Wert an den Callback schicken:</p>
<pre>FunkyObject.prototype.goCrazy = function() {
&nbsp;&nbsp;success = true;
&nbsp;&nbsp;this.trigger('load', success, 'ready', {hello: 'world'});
};</pre>
<h2>Fazit</h2>
<p>Ich mag Callbacks. Wenn man ein gutes Grundgerüst hat kann man auf alle Events individuell reagieren. Sollte es ein Callback nicht geben den man wirklich dringend und sofort benötigt kann man mit dem Überschreiben der <code>prototype</code> Funktion kurzfristig neue Callbacks hinzufügen und später in die Core Anwendung übernehmen.</p>
<p>Wichtig ist aber darauf zu achten keine unendlichen Scripte in den Callbacks unterzubringen. Spätestens nach 20 Zeilen sollte man sich überlegen den Code in einzelne Häppchen aufzuteilen.</p>
<p>Und in eigener Sache noch die Warnung vor gedankenlosem Copy and Paste: Durch Unterschrift auf dem NDA musste ich alle Funktionen umbenennen. Also nachdenken und gute Funktionsnamen benutzen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2011/12/07/schones-javascript-mit-callbacks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Viele Elemente dynamisch aktualisieren</title>
		<link>http://www.interaktionsdesigner.de/2009/07/24/viele-elemente-dynamisch-aktualisieren/</link>
		<comments>http://www.interaktionsdesigner.de/2009/07/24/viele-elemente-dynamisch-aktualisieren/#comments</comments>
		<pubDate>Fri, 24 Jul 2009 18:10:57 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=555</guid>
		<description><![CDATA[Ein aktuelles Projekt interagiert auf sehr starke Art und Weise mit dem Benutzer. Das bedeutet neben einer anpassbaren Oberfläche wird der Benutzer ständig über den Status diverser Objekte auf dem laufenden gehalten. Dabei können sich verschiedene Objekte untereinander beeinflussen. jQuery bietet ja ein tolles Ajaxkonstrukt an mit dem es kein Problem ist Daten vom Server [...]]]></description>
			<content:encoded><![CDATA[<p>Ein aktuelles Projekt interagiert auf sehr starke Art und Weise mit dem Benutzer. Das bedeutet neben einer anpassbaren Oberfläche wird der Benutzer <strong>ständig über den Status</strong> diverser Objekte auf dem laufenden gehalten. Dabei können sich verschiedene Objekte untereinander beeinflussen.</p>
<p>jQuery bietet ja ein tolles Ajaxkonstrukt an mit dem es kein Problem ist Daten vom Server zu holen. Aber auf die Dauer wird es doch etwas nervig immer wieder zu tippen.</p>
<p>Und weil <strong>"objektorientiertes Javascript"</strong> und selber entwickeln so viel <strong>Spaß</strong> macht, habe ich mir eine alternative Lösung einfallen lassen: Im Projekt werden an geeigneter Stelle <em>Elemente</em> erzeugt, die alle benötigten Informationen enthalten.</p>
<p>Diese werden in einem <em>Updater</em> registriert, welcher sich um die regelmäßige Abfrage kümmert. Das war die Theorie und jetzt kommt die <strong>Praxis</strong>.</p>
<p><span id="more-555"></span></p>
<h2>Das Element</h2>
<p>Ein Element besteht aus <strong>einer URL</strong> auf dem Server, <strong>dem Typ</strong> der zurückerwartenden Daten und <strong>einer Funktion</strong> die aufgerufen wird, wenn die Aktion erfolg hatte. Im Quelltext sieht das so aus:</p>
<pre>var Paul = new element('count/paul', 'json', function(j) {
&nbsp;&nbsp;alert("Paul hat "+j.count+" Einträge.");
});</pre>
<p>Diese Elemente können überall im Projekt erzeugt werden. Alternativen zu <em>json</em> sind alle Formen die jQuerys Ajaxfunktion erkennt: <em>Html</em>, <em>Text</em> und <em>Jsonp</em>.</p>
<h2>Der Updater</h2>
<p>Ganz am Anfang (oder am Ende, je nach Geschmack) wird der Updater initalisiert:</p>
<pre>var Updater = new updater();</pre>
<p>Der Updater akzeptiert zwei Einstellungen:</p>
<pre>Updater.intervall = 1000; // Zeit bis zur nächsten Abfrage
Updater.baseurl = "http://kleiner.test.com/"; // String der vor jede URL geschrieben wird</pre>
<p>Und hat eine handvoll Funktionen für den dynamischen Umgang mit dem Objekt:</p>
<pre>Updater.start(); // Startet den Vorgang sofern Elemente vorhanden sind
Updater.stop(); // Stoppt die Aktualisierungen
Updater.isRunning(); // Prüft ob sich der Updater in Aktion befindet
Updater.log(); // Schreibt alle gespeicherten Elementen in die Konsole
Updater.register(Element); // Fügt ein neues Element hinzu
Updater.remove(Element); // Entfernt ein Element</pre>
<h2>Die Verwendung</h2>
<p>Dem Updater werden <strong>beliebig viele Elemente</strong>, auch zur Laufzeit, übergeben:</p>
<pre>Updater.register(Paul);
Updater.start();</pre>
<p>Das wars! Die Funktion im übergebenen Element wird jetzt, im erfolgsfall, alle 1000 Millisekunden aufgerufen.</p>
<h2>Die technische Seite vom Element</h2>
<p>So sieht das Element aus:</p>
<pre style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#3f7bc6;">function</span> <span style="color:#4080ff;">element</span>(url, dataType, successFunction) {

  <span style="color:#e27600;">//einstellungen
</span>  <span style="color:#3f7bc6;">this</span>.url = url;
  <span style="color:#3f7bc6;">this</span>.data = {};
  <span style="color:#3f7bc6;">this</span>.type = <span style="color:#df2800;">'get'</span>
  <span style="color:#3f7bc6;">this</span>.dataType = dataType || <span style="color:#df2800;">'html'</span>;

  <span style="color:#e27600;">//callback um die daten zu bekommen
</span>  <span style="color:#3f7bc6;">this</span>.getData = <span style="color:#3f7bc6;">function</span>() {
    <span style="color:#3f7bc6;">return</span> <span style="color:#3f7bc6;">this</span>.data;
  }

  <span style="color:#e27600;">//callback um an die URL zu kommen
</span>  <span style="color:#e27600;">//erster parameter ist die im Updater gespeicherte baseurl
</span>  <span style="color:#3f7bc6;">this</span>.getUrl = <span style="color:#3f7bc6;">function</span>(BASEURL) {
    <span style="color:#3f7bc6;">return</span> <span style="color:#3f7bc6;">this</span>.url;
  }

  <span style="color:#e27600;">//callback wenn eine antwort vorliegt
</span>  <span style="color:#e27600;">//erster Parameter ist die Antwort vom Server, zweiter der Updater an sich
</span>  <span style="color:#3f7bc6;">this</span>.success = successFunction || <span style="color:#3f7bc6;">function</span>(html, Updater) {
    console.<span style="color:#4080ff;">log</span>(<span style="color:#df2800;">'Anfrage #'</span>+Updater.counter);
    console.<span style="color:#4080ff;">log</span>(html);
  }

  <span style="color:#e27600;">//callback wenn ein fehler aufgetreten ist
</span>  <span style="color:#e27600;">//erster parameter ist der Updater an sich um dieses Element daraus zu entfernen
</span>  <span style="color:#3f7bc6;">this</span>.error = <span style="color:#3f7bc6;">function</span>(Updater) {
    <span style="color:#e27600;">//bei einem fehler entfernt sich das objekt selbstständig aus dem updater
</span>    Updater.<span style="color:#4080ff;">remove</span>(<span style="color:#3f7bc6;">this</span>);
  }

}</pre>
<p>Zwei Funktionen sind wichtig: <strong>getData()</strong> wird aufgerufen, bevor die Anfrage an den Server gesendet wird. Der Rückgabewert der Funktion wird an den Server geschickt.</p>
<p>Damit ist es also möglich, auf <strong>Veränderungen im Frontend</strong> zu reagieren. Zum Beispiel:</p>
<pre>Paul.getData = function() {
&nbsp;&nbsp;return {relation: $('body').attr('rel'), project: $('#project_selector').val()};
}</pre>
<p>Schön, oder? Natürlich kann man sich noch viel einfallen lassen. Etwa mit der URL, welche mit Hilfe der Funktion <strong>getUrl()</strong> aus dem Element geholt wird. Es soll ja Fälle geben (<em>CakePHP</em>), bei denen es leichter ist Daten per URL zu übergeben:</p>
<pre>Paul.getUrl = function(BASEURL) {
&nbsp;&nbsp;return BASEURL+this.url+'/'+$('#team .paul').attr('rel');
}</pre>
<p>Die Funktionen <strong>success(return, Updater)</strong> und <strong>error(Updater)</strong> erklären sich von selbst und haben als Parameter immer das umfassende Element dabei. Deshalb kann sich das Objekt in einem Fehlerfall auch selbstständig entfernen. Es könnte auch das Intervall verändern, ein neues Objekt hinuzfügen, oder was auch immer!</p>
<h2>Die technische Seite vom Updater</h2>
<p>Als erstes der gesamte Block Quelltext:</p>
<pre style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#3f7bc6;">function</span> <span style="color:#4080ff;">updater</span>() {

  <span style="color:#e27600;">//einstellungen
</span>  <span style="color:#3f7bc6;">this</span>.intervall = <span style="color:#fe2d00;">1000</span>;
  <span style="color:#3f7bc6;">this</span>.elements = <span style="color:#3f7bc6;">new</span> <span style="color:#4080ff;">Array</span>();
  <span style="color:#3f7bc6;">this</span>.active_element = <span style="color:#fe2d00;">0</span>;
  <span style="color:#3f7bc6;">this</span>.baseurl = BASEURL;

  <span style="color:#3f7bc6;">this</span>.running = <span style="color:#3f7bc6;">false</span>;
  <span style="color:#3f7bc6;">this</span>.counter = <span style="color:#fe2d00;">0</span>;
  <span style="color:#3f7bc6;">this</span>.timeout = <span style="color:#df2800;">''</span>;

  <span style="color:#e27600;">//alle elemente anzeigen
</span>  <span style="color:#3f7bc6;">this</span>.log = <span style="color:#3f7bc6;">function</span>() {
    console.<span style="color:#4080ff;">log</span>(<span style="color:#3f7bc6;">this</span>.elements);
  }

  <span style="color:#e27600;">//neues element hinzufügen
</span>  <span style="color:#3f7bc6;">this</span>.register = <span style="color:#3f7bc6;">function</span>(element) {
    <span style="color:#3f7bc6;">this</span>.elements.<span style="color:#4080ff;">push</span>(element);
  };

  <span style="color:#e27600;">//ein element entfernen
</span>  <span style="color:#3f7bc6;">this</span>.remove = <span style="color:#3f7bc6;">function</span>(element) {
    <span style="color:#3f7bc6;">for</span>(i <span style="color:#3f7bc6;">in</span> <span style="color:#3f7bc6;">this</span>.elements) {
      <span style="color:#3f7bc6;">if</span>(<span style="color:#3f7bc6;">this</span>.elements[i] == element) {
        <span style="color:#e27600;">//delete this.elements[i];
</span>        <span style="color:#3f7bc6;">this</span>.elements.<span style="color:#4080ff;">splice</span>(i, <span style="color:#fe2d00;">1</span>);
        <span style="color:#3f7bc6;">return</span> <span style="color:#3f7bc6;">true</span>;
      }
    }
    <span style="color:#3f7bc6;">return</span> <span style="color:#3f7bc6;">false</span>;
  }

  <span style="color:#e27600;">//elemente durchgehen
</span>  <span style="color:#3f7bc6;">this</span>.process = <span style="color:#3f7bc6;">function</span>(active_element) {
    <span style="color:#3f7bc6;">this</span>.active_element = active_element || <span style="color:#fe2d00;">0</span>;

    <span style="color:#3f7bc6;">if</span>(<span style="color:#3f7bc6;">this</span>.elements[<span style="color:#3f7bc6;">this</span>.active_element]) {
      _this = <span style="color:#3f7bc6;">this</span>;
      _elem = <span style="color:#3f7bc6;">this</span>.elements[<span style="color:#3f7bc6;">this</span>.active_element];

      <span style="color:#e27600;">//ajaxaufruf
</span>      $.<span style="color:#4080ff;">ajax</span>({
        <span style="color:#e27600;">//einstellungen
</span>        url: _elem.<span style="color:#4080ff;">getUrl</span>(_this.baseurl),
        data: _elem.<span style="color:#4080ff;">getData</span>(),
        type: _elem.type,
        dataType: _elem.dataType,

        <span style="color:#e27600;">//hat funktioniert!
</span>        success: <span style="color:#3f7bc6;">function</span>(result) {
          _elem.<span style="color:#4080ff;">success</span>(result, _this);
        },

        <span style="color:#e27600;">//ein fehler
</span>        error: <span style="color:#3f7bc6;">function</span>(error) {
          <span style="color:#e27600;">//das object soll entscheiden wie es weitergeht
</span>          _elem.<span style="color:#4080ff;">error</span>(_this);
        },

        <span style="color:#e27600;">//wie auch immer soll das nächste element aufgerufen werden
</span>        complete: <span style="color:#3f7bc6;">function</span>() {
          _this.<span style="color:#4080ff;">next</span>();
        }
      });     

    }
    <span style="color:#3f7bc6;">else</span> {
      <span style="color:#3f7bc6;">this</span>.active_element = <span style="color:#fe2d00;">0</span>;
      <span style="color:#3f7bc6;">this</span>.<span style="color:#4080ff;">next</span>();
    }
  };

  <span style="color:#e27600;">//ruft process erneut auf, verzögert um intervall mit dem activen element
</span>  <span style="color:#3f7bc6;">this</span>.next = <span style="color:#3f7bc6;">function</span>() {
    <span style="color:#3f7bc6;">if</span>(<span style="color:#3f7bc6;">this</span>.<span style="color:#4080ff;">isRunning</span>()) {
      <span style="color:#e27600;">//nur so zum spaß
</span>      <span style="color:#3f7bc6;">this</span>.counter++;

      <span style="color:#e27600;">//zeit die bis zum nächsten aufruf vergehen soll
</span>      <span style="color:#3f7bc6;">var</span> _intervall = <span style="color:#fe2d00;">0</span>;

      <span style="color:#e27600;">//nächstes element suchen
</span>      <span style="color:#3f7bc6;">this</span>.active_element++;

      <span style="color:#e27600;">//schon am ende angelangt?
</span>      <span style="color:#3f7bc6;">if</span>(<span style="color:#3f7bc6;">this</span>.active_element &gt;= <span style="color:#3f7bc6;">this</span>.elements.length) {
        <span style="color:#3f7bc6;">this</span>.active_element = <span style="color:#fe2d00;">0</span>;

        <span style="color:#e27600;">//längerer intervall bis es wieder los geht
</span>        _intervall = <span style="color:#3f7bc6;">this</span>.intervall;
      }

      <span style="color:#e27600;">//erneut aufrufen
</span>      _this = <span style="color:#3f7bc6;">this</span>;
      _this.timeout = window.<span style="color:#4080ff;">setTimeout</span>(<span style="color:#3f7bc6;">function</span>() {
        _this.<span style="color:#4080ff;">process</span>(_this.active_element);
      }, _intervall);
      <span style="color:#3f7bc6;">return</span> <span style="color:#3f7bc6;">true</span>;
    }
    <span style="color:#3f7bc6;">else</span> {
      <span style="color:#3f7bc6;">return</span> <span style="color:#3f7bc6;">false</span>;
    }
  }

  <span style="color:#e27600;">//startet den vorgang
</span>  <span style="color:#3f7bc6;">this</span>.start = <span style="color:#3f7bc6;">function</span>() {
    <span style="color:#3f7bc6;">this</span>.active_element = -<span style="color:#fe2d00;">1</span>;
    <span style="color:#3f7bc6;">this</span>.running = <span style="color:#3f7bc6;">true</span>;
    <span style="color:#3f7bc6;">this</span>.counter = <span style="color:#fe2d00;">0</span>;
    <span style="color:#3f7bc6;">this</span>.<span style="color:#4080ff;">next</span>();
  }

  <span style="color:#e27600;">//stoppt das updaten
</span>  <span style="color:#3f7bc6;">this</span>.stop = <span style="color:#3f7bc6;">function</span>() {
    <span style="color:#3f7bc6;">this</span>.running = <span style="color:#3f7bc6;">false</span>;
    window.<span style="color:#4080ff;">clearTimeout</span>(<span style="color:#3f7bc6;">this</span>.timeout);
    <span style="color:#3f7bc6;">return</span> <span style="color:#3f7bc6;">this</span>.counter;
  }

  <span style="color:#e27600;">//prüfen ob der Updater läuft
</span>  <span style="color:#3f7bc6;">this</span>.isRunning = <span style="color:#3f7bc6;">function</span>() {
    <span style="color:#3f7bc6;">return</span> <span style="color:#3f7bc6;">this</span>.running;
  }
}</pre>
<p>Nett, oder? Was ist passiert? Die Einstellungen sollten klar sein. In der Variable <strong>timeout</strong> wird der aktuelle Timeout gespeichert. Damit kann man beim Abbrechen alle Verbindungen trennen, anstatt noch eine ausführen zu müssen.</p>
<p><strong>Log()</strong>, <strong>register()</strong> und <strong>remove()</strong> sind an sich uninteressant. Außer eine Erwähnung, dass der Operator <em>delete</em> ein Element zwar entfernt, aber danach nicht das Array neu durchnummeriert. Da liegen dann lauter "<em>undefinied</em>" rum. Deshalb habe ich <strong>splice()</strong> benutzt. Funktioniert super.</p>
<p>Spannend wird es in der Funktion <strong>process()</strong>. Diese wird für jedes Element aufgerufen. Als Parameter erwartet sie den <strong>Key</strong> vom aktiven Element. Wenn ein Element vorhanden ist, wird die Ajaxabfrage ausgeführt.</p>
<p>Innerhalb der Funktion Ajax() bekommt das <em>this</em> eine neue Bedeutung. Deshalb musste ich es in <em>_this</em> zwischenspeichern.</p>
<p>Die Funktion ruft also, je nach umstand, <strong>success()</strong> oder <strong>error()</strong> auf und übergibt die Kontrolle an das Element. In jedemfall wird aber <strong>_this.next()</strong> durch die Funktion <strong>Ajax.complete()</strong> aufgerufen. Diese wird, unabhängig vom Status, nach jeder Ajaxanfrage ausgeführt.</p>
<p>In der Funktion <strong>next()</strong> wird das nächste Objekt gesucht. Sofern der Updater läuft <strong>isRunning() </strong>wird der Counter erhöht und das Intervall auf Null gesetzt. Das passiert, weil alle registrierten Elemente sofort nacheinander aufgerufen werden sollen und erst anschließend die in <em>this.intervall</em> angegebene Zeit gewartet wird.</p>
<p>Wenn alle Elemente durchgearbeitet wurden, wird der <strong>Index auf Null</strong> und der <strong>Intervall auf die eingestellte Zeit</strong> gesetzt.</p>
<p>Anschließend gibt es ein klassisches <strong>window.setTimeout()</strong> um das ganze Spielchen wieder von vorne anzufangen.</p>
<p><strong>Start()</strong>, <strong>stop()</strong> und <strong>isRunning()</strong> erklären sich wieder von selbst, und damit ist die Vorstellung beendet!</p>
<h2>Fazit</h2>
<p>Der große nächste Erweiterungsschritt ist in dem Updater alle Anfragen zu sammeln und<strong> in einem Packet</strong> an den Server zu schicken. Die Antwort kann dann direkt vom Updater auseinander gefriemelt und an die verschiedenen Elemente verteilt werden.</p>
<p>Dazu muss der Server allerdings noch vorbereitet werden, und bisher sind es noch nicht viele Benutzer. Aber ich denke es ist eine <strong>solide Grundlage</strong> die gut erweitert werden kann.</p>
<p>Das war auch die Intention dieses Postings. Hast du einen <strong>Vorschlag</strong>? <strong>Kritik</strong>? <strong>Hinweis</strong>? Freue mich über Kommentare und Inspiration. Danke für die Aufmerksamkeit.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2009/07/24/viele-elemente-dynamisch-aktualisieren/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Automatisch erkennen wie CSV Dateien aufgebaut sind</title>
		<link>http://www.interaktionsdesigner.de/2009/02/25/automatisch-erkennen-wie-csv-dateien-aufgebaut-sind/</link>
		<comments>http://www.interaktionsdesigner.de/2009/02/25/automatisch-erkennen-wie-csv-dateien-aufgebaut-sind/#comments</comments>
		<pubDate>Wed, 25 Feb 2009 17:04:49 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=285</guid>
		<description><![CDATA[CSV Dateien sind z.B. Exports aus Datenbanken oder Excel. Der Name steht für Comma-Separated Values und bedeutet, dass die Werte von einem Komma getrennt sind. Damit kann man einfach eine CSV importieren und zum Beispiel in PHP weiter verarbeiten. Tja, einfach ist das natürlich nicht und jedes Programm erstellt andere CSV Dateien. Ich habe eine [...]]]></description>
			<content:encoded><![CDATA[<p>CSV Dateien sind z.B. <strong>Exports aus Datenbanken oder Excel</strong>. Der Name steht für <em>Comma-Separated Values </em>und bedeutet, dass die Werte von einem Komma getrennt sind. Damit kann man <strong>einfach</strong> eine CSV importieren und zum Beispiel in PHP weiter verarbeiten.</p>
<p>Tja, einfach ist das natürlich nicht und jedes Programm erstellt <strong>andere CSV Dateien</strong>. Ich habe eine Funktion geschrieben die versucht <strong>automatisch</strong> zu erkennen wie eine CSV Datei aufgebaut ist. <a title="Automatische CSV Erkennung" href="http://interaktionsdesigner.de/stuff/csv.php" target="_blank">Hier ist eine Demo</a> und im folgenden Artikel kommt die Funktionsweise.<span id="more-285"></span>Die Funktion erwartet einen String, z.B. <pre>"spalte1", "spalte2", "spalte3"</pre> und gibt dann ein Array zurück mit den Keys <em>delimiter</em> und <em>enclosure</em>. Aus dem obrigen Beispiel wäre das dann <pre>Array(&nbsp;&nbsp;[delimiter] =&gt; ; &nbsp;&nbsp;[enclosure] =&gt; ")</pre></p>
<p>Hier kommt die <strong>komplette Funktion</strong> und anschließend ein paar erklärende Worte.<pre>function csv_autodetect($string) {
&nbsp;&nbsp;$str = trim($string);
&nbsp;&nbsp;$char = '';
&nbsp;&nbsp;$e = '';
&nbsp;&nbsp;$d = array();
&nbsp;&nbsp;$open = false;
&nbsp;&nbsp;$strip = false;
&nbsp;&nbsp;for($i = 0; $i &lt; strlen($str); $i++) {
&nbsp;&nbsp;&nbsp;&nbsp;$char = $str[$i];
&nbsp;&nbsp;&nbsp;&nbsp;if(preg_match('=[\W]=', $char) &amp;&amp; ord($char) != 32) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($i == 0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$e = $char;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($char == '\\')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$strip = true;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$strip = false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($char == $e &amp;&amp; !$strip) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$open = $open ? false : true;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!$open &amp;&amp; !$strip)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$d[$char]++;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;}
&nbsp;&nbsp;
&nbsp;&nbsp;asort($d);
&nbsp;&nbsp;$dd = array_keys($d, array_pop($d));
&nbsp;&nbsp;$return['delimiter'] = $dd[0];
&nbsp;&nbsp;$return['enclosure'] = $e;
&nbsp;&nbsp;return $return;&nbsp;&nbsp;
}</pre></p>
<p>Nachdem einige Variablen vorbelegt wurden, erfolgt die <strong>zeichenweise Untersuchung des Strings</strong>. Wenn es sich um ein Sonderzeichen handelt, dann beginnt die Untersuchung.</p>
<p><pre>if($i == 0)
&nbsp;&nbsp;$e = $char;</pre>Wenn das erste Zeichen des Strings ein <strong>Sonderzeichen</strong> ist und kein Leerzeichen, dann ist es mit Sicherheit jenes, welches die Werte umfasst (<em>e = Enclosure</em>).<br />
<pre>if($char == '\\')
&nbsp;&nbsp;$strip = true;
else
&nbsp;&nbsp;$strip = false;</pre>Wenn es sich um ein <strong>Backslash</strong> handelt, dann wird das nächste Zeichen ignoriert. Damit sind dann Fälle wie <em>"eine \"Spalte\"";</em> auch möglich.<br />
<pre>if($char == $e &amp;&amp; !$strip)
$open = $open ? false : true;</pre>Wenn es also das umschließende Zeichen ist, und nicht durch ein Backslash auskommentiert wurde (<em>$strip</em>), dann wird der Status von <em>$open</em> geändert. Durch diese Beachtung ist es dann möglich den Delimeter innerhalb einer Spaltenbezeichnung zu benutzen (z.B. <em>"spalte1", "spalte1,5", "spalte2"</em>). Wenn es sich nicht um das umschließende Zeichen handelt, dann muss weiter überlegt werden:<br />
<pre>if(!$open &amp;&amp; !$strip)
&nbsp;&nbsp;$d[$char]++;</pre>Wenn sich das Zeichen nicht innerhalb einer Spaltenbezeichnung befindet und auch nicht auskommentiert wurde, dann wird das Arrayelement <em>$d</em> (<em>d = Delimiter</em>) mit dem Zeichen als Schlüssel um eins erhöht.</p>
<p>Der Grund dafür ist das eventuelle Auftreten von Sonderzeichen in einer Spaltenbezeichnung ohne Enclosure (z.B. spalte1, spalte2&amp;3, spalte4). Am Ende wird das Zeichen als Delimeter erwartet welches <strong>am häufigsten gefunden</strong> wurde. Das gibt zwar ein Problem bei einem String wie <em>c&amp;a, p&amp;c, m&amp;m</em> - aber dann muss man seine Felder halt mit einem Zeichen umschließen.</p>
<p><strong>Ende!</strong> Wer jetzt in seinem Kopf die Idee spinnt daraus ein Tool zu bauen welches <strong>CSV Dateien in eine Datenbank importiert</strong>, dem sei geraten noch ein paar Tage zu warten oder mir eine Mail zu schicken. Hab da was tolles in der mache was demnächst veröffentlicht wird <img src='http://www.interaktionsdesigner.de/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<p>Wer <em>Ideen</em>, <em>Probleme</em> und <em>Verbesserungsvorschläge</em> hat kann diese gerne in den Kommentaren los werden.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2009/02/25/automatisch-erkennen-wie-csv-dateien-aufgebaut-sind/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>processDatamap_postProcessFieldArray()</title>
		<link>http://www.interaktionsdesigner.de/2008/09/25/processdatamap_postprocessfieldarray/</link>
		<comments>http://www.interaktionsdesigner.de/2008/09/25/processdatamap_postprocessfieldarray/#comments</comments>
		<pubDate>Thu, 25 Sep 2008 16:41:06 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[TYPO3]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=83</guid>
		<description><![CDATA[Manchmal hasst man TYPO3 für diese Funktionsnamen. Wenn man dann durchschaut hat, was damit gemeint ist, verliebt man sich wieder in das riesen CMS. In diesem Beitrag will ich erklären wie es dank Hooks und dem TCEMain Objekt möglich wird, in die TYPO3 internen Speicherfunktionen zu kommen. Das braucht man für seine eigenen Extensions oder [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-84" title="TYPO3 Logo" src="http://www.interaktionsdesigner.de/wp-content/uploads/2008/09/logo_save-area_01.jpg" alt="TYPO3 Entwicklung und Liebe" width="334" height="141" />Manchmal hasst man TYPO3 für diese Funktionsnamen. Wenn man dann durchschaut hat, was damit gemeint ist, verliebt man sich wieder in das riesen CMS.</p>
<p>In diesem Beitrag will ich erklären wie es dank Hooks und dem TCEMain Objekt möglich wird, in die TYPO3 internen Speicherfunktionen zu kommen. Das braucht man für seine eigenen Extensions oder wenn man vor dem Speichern die Daten manipulieren möchte.<span id="more-83"></span><br />
Vorne weg sei gesagt, dass Robert Lemke schon ein <a href="http://typo3.org/development/articles/how-to-use-existing-hooks/" target="_blank">ausführliches, englisches Tutorial</a> geschrieben hat welches die Sache sehr gut und ansehnlich erklärt. Wer nicht so viel Zeit hat oder keine Lust auf Englisch, dem wünsche ich viel Spaß!</p>
<h2>Eine eigene Klasse</h2>
<p>Wir brauchen eine neue Datei in der wir unsere eigene Funktionalität festhalten. Diese braucht eine einzige Funktion, welche schon im Titel erwähnt ist: <strong>processDatamap_postProcessFieldArray</strong>.</p>
<pre><code class="php">class tx_EXTNAME_tcemainprocdm {
	function processDatamap_postProcessFieldArray($status, $table, $id, &amp;$fieldArray) {
		// ACTION!
	}
}</code></pre>
<p><em>EXTNAME</em> ist hier wie im folgenden stets entsprechend anzupassen.<br />
Wir erstellen also eine Funktion die eine ganze Reihe Parameter bekommt. Bei Robert Lemke hat sie auch noch ein <strong>&amp;$this</strong> als letzten Parameter, da hat er bei mir aber rumgemeckert.<br />
<strong>$status</strong> beinhaltet die gewählte Aktion (z.B. "update" oder "insert").<br />
In <strong>$table</strong> steht die Tabelle um die es geht.<br />
Und <strong>$id</strong> kennzeichnet den betreffenden Datensatz. Reicht für meine Zwecke.</p>
<h2>Den Hook registrieren</h2>
<p>Dafür wechseln wir in die Datei <strong>ext_localconf.php</strong> und fügen eine Zeile hinzu, welche unsere Klasse referenziert:</p>
<pre><code class="php">$GLOBALS["TYPO3_CONF_VARS"]["SC_OPTIONS"]["t3lib/class.t3lib_tcemain.php"]["processDatamapClass"][] = "EXT:EXTNAME/class.tx_EXTNAME_tcemainprocdm.php:tx_EXTNAME_tcemainprocdm";</code></pre>
<p>Der Datei <strong>t3lib_tcemain.php</strong> wird also unser Hook zugeteilt. Es ist darauf zu achten das dem Array ein neues Element hinzugefügt wird und durch das Konstrukt <em>Dateipfad<strong>:</strong>Klassenname</em> die Einbindung mittels <em>require</em> entfällt. Praktisch!</p>
<h2>Das wars!</h2>
<p>Nichts leichter als das. Wenn man mit Echo in der eigenen Funktion etwas ausgibt erscheint es nach dem Speichern eines Datensatzes über der Leiste mit den Speichernknöpfen, also keine Hemmungen und viel Spaß mit dem Logikmonster TYPO3!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2008/09/25/processdatamap_postprocessfieldarray/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PDF Formulare im Acrobat besiegen</title>
		<link>http://www.interaktionsdesigner.de/2008/09/10/pdf-formulare-im-acrobat-besiegen/</link>
		<comments>http://www.interaktionsdesigner.de/2008/09/10/pdf-formulare-im-acrobat-besiegen/#comments</comments>
		<pubDate>Wed, 10 Sep 2008 08:15:54 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=77</guid>
		<description><![CDATA[Der (verdammte) Acrobat bietet die Möglichkeit interaktive Formulare zu erstellen. Und kaum erstellt jemand ein Formular, fallen ihm diverse Abhängigkeiten und Sonderfunktionen ein, die es abzubilden gilt. Zum Glück ist es möglich mit JavaScript dynamisch auf die Eingaben zu reagieren, aber einfacher macht es die Sache nicht gerade. Hier kommt eine kleine Anleitung wie man [...]]]></description>
			<content:encoded><![CDATA[<p>Der (verdammte) Acrobat bietet die Möglichkeit interaktive Formulare zu erstellen. Und kaum erstellt jemand ein Formular, fallen ihm diverse Abhängigkeiten und Sonderfunktionen ein, die es abzubilden gilt. Zum Glück ist es möglich mit JavaScript dynamisch auf die Eingaben zu reagieren, aber einfacher macht es die Sache nicht gerade.</p>
<p>Hier kommt eine kleine Anleitung wie man den Inhalt auf Buchstaben und Leerzeichen überprüft und eine Abhängigkeit von mehreren "Kontrollkästchen" - auch Checkboxen genannt - erzeugt.<span id="more-77"></span></p>
<h2>Grundlegend</h2>
<p>In den JavaScripten gibt es zwei Objekte die für mich interessant sind.</p>
<pre>this</pre>
<p>Bezieht sich auf das gesamte Dokument und beinhaltet u.a. alle Formularfelder.</p>
<pre>event</pre>
<p>Beinhaltet das aktuelle, angeklickte Element und erlaubt den Status zu setzen.</p>
<h2>1. Inhalt auf "echte Zeichen" überprüfen</h2>
<p>Wir haben ein Textfeld zur Eingabe von Formulardaten. Hinter einem Doppelklick verstecken sich die Feldeigenschaften. Hinter dem Button "Validierung" gibt es die Möglichkeit ein "Benutzerdefiniertes Validierungsscript aus(zu)führen". Perfekt. Nehmen wir, und so siehts aus:</p>
<pre><code class="javascript">if(event.value.search(/[^a-z ]/gi) == -1) {
    event.rc = true;
}
else {
  event.rc = false;
  app.alert("Bitte geben Sie nur Buchstaben ein.");
}</code></pre>
<p>Über die Eigenschaft <strong>event.value</strong> bekommen wir den Inhalt des Formularfeldes nach der Eingabe (das regelt das PDF für uns). Mit der Funktion <a href="http://de.selfhtml.org/javascript/objekte/string.htm#search" target="_blank">search()</a> wende ich einen regulären Ausdruck auf den Inhalt an. <em>[a-z ]</em> trifft auf alle Buchstaben und das Leerzeichen zu. Mit "i" wird die Groß- und Kleinschreibung ignoriert und "g" durchsucht den String bis zum Ende. Mit dem Dach (^) negieren wir die Auswahl - wird also nichts anderes außer Buchstaben oder das Leerzeichen gefunden, ist alles in Ordnung und der <strong>Return Code (rc)</strong> wird positiv; der Inhalt hat die Validierung bestanden (<a href="http://www.addedbytes.com/cheat-sheets/regular-expressions-cheat-sheet/" target="_blank">bei AddedBytes gibts ein gutes Cheat Sheet zu regulären Ausdrücken</a>).<br />
Ist dies <strong>nicht</strong> der Fall, negieren wir den Return Code, was ein verlassen des Feldes verhindert, bzw. den Standardwert setzt. Über <strong>app.alert()</strong> wird der Benutzer noch darauf hingewiesen (ohne <strong>app</strong> funktioniert es nicht).</p>
<h2>2. Abhängigkeiten von Checkboxen</h2>
<p>Das Problem: Wenn eine Checkbox gewählt ist, dann dürfen eine ganze Reihe <strong>anderer</strong> Felder <strong>nicht</strong> ausgewählt werden. Alltäglich...<br />
Bei den Checkboxen gibt es keine Validierung, deshalb fügen wir eine neue Aktion hinzu: Bei <em>"Maustaste loslassen"</em> wird ein JavaScript ausgeführt, undzwar folgendes.</p>
<pre><code class="javascript">if(this.getField("FELDNAME_1").value == "VALUE_1") {
  this.resetForm(["FELDNAME_2"]);
}</code></pre>
<p>Bedeutet: über <strong>this.getField().value</strong> bekommen wir den Inhalt der ersten Checkbox (mit Namen FELDNAME_1), welche die Abhängigkeit auslösen soll. Ist sie nicht ausgewählt, besitzt sie auch keinen Inhalt (VALUE_1).<br />
Falls doch, wird mit <strong>this.resetForm()</strong> der Standard wieder hergestellt. Als Parameter wird der Feldname als Array übergeben. Es könnten also auch mehrere Felder zurück gesetzt werden mit <em>resetForm(["FELD_1", "FELD_2"])</em> - man achte auf die korrekte Klammerung.</p>
<h2>Fazit</h2>
<p>Alles in allem eine ehr anstrengende Geschichte, aber ich denke sie funktioniert. Die Informationen im Netz sind spärlich, geholfen hat mir aber das endlose PDF<a href="http://www.adobe.com/devnet/acrobat/javascript.html" target="_blank"> JavaScript in Acrobar API</a>. Die <a href="http://help.adobe.com/de_DE/Acrobat/9.0/Standard/WS58a04a822e3e50102bd615109794195ff-7e1e.w.html" target="_blank">offizielle Acrobat Hilfe</a> bietet einen ersten Einstieg - und setzt erfreulicher Weise auf jQuery <img src='http://www.interaktionsdesigner.de/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2008/09/10/pdf-formulare-im-acrobat-besiegen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Schöner Lokal entwickeln</title>
		<link>http://www.interaktionsdesigner.de/2008/08/09/schoner-lokal-entwickeln/</link>
		<comments>http://www.interaktionsdesigner.de/2008/08/09/schoner-lokal-entwickeln/#comments</comments>
		<pubDate>Sat, 09 Aug 2008 12:13:10 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=59</guid>
		<description><![CDATA[Mit einfachen Mitteln ist auf dem eigenen Rechner ein Webserver installiert und die Entwicklung von spannenden Projekten kann beginnen. Für die lokale Entwicklung ist das Directorylistning vom Apache Webserver schon sehr praktisch. Nur leider sieht es nicht besonders schön aus. Mit einfachen Mitteln lässt sich das aber sehr schnell ändern, und schon surft man voller [...]]]></description>
			<content:encoded><![CDATA[<p>Mit <a href="http://www.mamp.info/de/index.php" target="_blank">einfachen Mitteln</a> ist auf dem eigenen Rechner ein Webserver installiert und die Entwicklung von spannenden Projekten kann beginnen. Für die lokale Entwicklung ist das Directorylistning vom Apache Webserver schon sehr praktisch.</p>
<p><img class="aligncenter size-full wp-image-60" title="vorher" src="http://www.interaktionsdesigner.de/wp-content/uploads/2008/08/vorher.png" alt="" width="500" height="216" /></p>
<p>Nur leider sieht es nicht besonders schön aus. Mit einfachen Mitteln lässt sich das aber sehr schnell ändern, und schon surft man voller Freude durch die eigene Ordnerstruktur.<span id="more-59"></span><br />
So könnte man es machen:</p>
<p><strong>Standardschriftart im Browser ändern.</strong> Mit zweieinhalb Klicks ist Verdana oder Arial eingestellt was einen wesentlich angenehmeren Eindruck auf ungestylten Seiten hinterlässt. Im Firefox gehts über <em><br />
Einstellungen</em> &gt; <em>Inhalte</em> &gt; <em>Schriftarten und Farben</em>.</p>
<p><strong>Die htaccess im Heimatverzeichnis anpassen.</strong> Der Apache Webserver bietet umfangreiche Möglichkeiten um das Listning anzupassen. Besonders interessant wird es mit eigenen Header- und Footer-Dateien. So sieht es bei mir aus:</p>
<pre><code class="htaccess"># Serversignatur ausschalten. Ich weiß ja schon was ich für einen Server installiert habe.
ServerSignature Off

# Anzeigen vom Verzeichnisinhalt, sofern keine index.html/index.php vorhanden ist.
Options +Indexes

# Jetzt wirds verschönert!
IndexOptions HTMLTable FancyIndexing

# Einen eigenen Header einbinden. In dem ist Platz für CSS und JavaScript
HeaderName /server/header.html

# Wir brauchen überhaupt keinen Footer.
IndexIgnore footer.html

# Verhindern das die Tabelle in eigene Bodytags verschachtelt wird
IndexOptions SuppressHTMLPreamble

# Manchmal will man auch die kleinen Icons anklicken.
IndexOptions IconsAreLinks

# Zeigt die HTML Titel in den Beschreibungen an.
# Kommt aber selten zum Einsatz, da meistens eine index Datei vorhanden ist
IndexOptions ScanHTMLTitles

# Die Spalte Beschreibung soll lang genug sein
IndexOptions DescriptionWidth=*

# Und eine Standardsortierung. Die zickt aber manchmal rum...
IndexOrderDefault Ascending Name</code></pre>
<p>Das wars! Und schon sieht das ganze wesentlich angenehmer aus.</p>
<p><a href="http://www.interaktionsdesigner.de/wp-content/uploads/2008/08/nachher-1.png"><img class="aligncenter size-full wp-image-61" title="nachher-1" src="http://www.interaktionsdesigner.de/wp-content/uploads/2008/08/nachher-1.png" alt="" width="500" height="186" /></a></p>
<p>Tiefschürfende Informationen über alle Möglichen htaccess Einstellungen gibt es bei <a href="http://www.trash.net/faq/htaccess.shtml" target="_blank">trash.net</a> (de) oder direkt von den <a href="http://httpd.apache.org/docs/2.0/howto/htaccess.html" target="_blank">Machern</a> (en).</p>
<p>Wer keine Lust hat selber Dateien anzulegen, lädt sich <a href="http://www.interaktionsdesigner.de/stuff/htaccess.zip">dieses Archiv</a> runter und entpackt es in das Heimatverzeichnis des Webservers. In der <em>header.html</em> befindet sich das Styling welches die Ausgabe einfärbt.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2008/08/09/schoner-lokal-entwickeln/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Der einfachste Blindtextgenerator</title>
		<link>http://www.interaktionsdesigner.de/2008/08/07/der-einfachste-blindtextgenerator/</link>
		<comments>http://www.interaktionsdesigner.de/2008/08/07/der-einfachste-blindtextgenerator/#comments</comments>
		<pubDate>Thu, 07 Aug 2008 13:19:25 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=55</guid>
		<description><![CDATA[Der Trend geht dahin Webseiten nicht mehr mit ausschließlich mit Photoshop zu gestallten, sondern die Entwicklung direkt im Browser voran zu treiben. Das hat den Vorteil das interaktive Möglichkeiten schneller umgesetzt und besser kommuniziert werden können. Und was fehlt? Mengen an Blindtext! Da wir gerade ein neues Projekt auf diese Art und Weise begonnen haben, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.interaktionsdesigner.de/wp-content/uploads/2008/08/blindtext.png"><img class="alignright size-full wp-image-56" title="blindtext" src="http://www.interaktionsdesigner.de/wp-content/uploads/2008/08/blindtext.png" alt="" width="232" height="162" /></a>Der Trend geht dahin Webseiten nicht mehr mit ausschließlich mit Photoshop zu gestallten, sondern die Entwicklung direkt im Browser voran zu treiben. Das hat den Vorteil das interaktive Möglichkeiten schneller umgesetzt und besser kommuniziert werden können.</p>
<p>Und was fehlt? <strong>Mengen an Blindtext!</strong> Da wir gerade ein neues Projekt auf diese Art und Weise begonnen haben, standen wir vor genau diesem Problem. Es folgt ein einfacher Lösungsansatz mit PHP.<br />
<span id="more-55"></span></p>
<p>Wer jetzt Mengen an Text erwartet hat, den muss ich leider entäuschen. Ich habe eine Mini-PHP Klasse geschrieben: <em>Blindtext</em>.<br />
Diese besitzt genau eine Funktion: <em>get()</em>. Die Funktion kann aufgerufen werden ohne ein neues Objekt der Klasse zu erzeugen und kann mit zwei Parametern gesteuert werden. Die in Klammern gesetzten Werte sind die Standardwerte.</p>
<p><strong>$length</strong> (= 100) - Anzahl von Zeichen die der Blindtext enthalten soll<br />
<strong>$dot</strong> (= true) - Setzt einen Punkt an das Ende des Blindtexts, wenn true</p>
<p>So einfach! Das Besondere an der Klasse ist die dynamische Ausgabe. Es ist ein String (Lorem ipsum...) gespeichert von dem zufällig die ersten Zeichen abgeschnitten werden. Damit erhält man nicht immer den gleichen Blindtext.</p>
<p>So gehts:</p>
<pre><code class="php">&lt;?
  include("blindtext.php");
  echo blindtext::get(200);
?&gt;</code></pre>
<p>Ich spare mir jetzt mal die Ausgabe als Beispiel dazu zu schreiben.</p>
<p>Hier ist der <a href="http://www.interaktionsdesigner.de/stuff/blindtext.zip">download</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2008/08/07/der-einfachste-blindtextgenerator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Aus der Mitte entspringt ein RTE</title>
		<link>http://www.interaktionsdesigner.de/2008/07/28/aus-der-mitte-entspringt-ein-rte/</link>
		<comments>http://www.interaktionsdesigner.de/2008/07/28/aus-der-mitte-entspringt-ein-rte/#comments</comments>
		<pubDate>Mon, 28 Jul 2008 14:44:14 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[TYPO3]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=54</guid>
		<description><![CDATA[Zur Zeit entwickle ich meine erste große TYPO3 Extension die das Aktualisieren der Inhalte für Redakteure und Administratoren vereinfachen soll. Dazu demnächst mehr - erstmal geht es um die Konfiguration des RTE. Es ist unglaublich wie viele verschiedene Ansätze es dazu gibt, wie weit sich die Konfiguration verschachteln lässt und wie unglaublich nervig das werden [...]]]></description>
			<content:encoded><![CDATA[<p>Zur Zeit entwickle ich meine erste große TYPO3 Extension die das Aktualisieren der Inhalte für Redakteure und Administratoren vereinfachen soll. Dazu demnächst mehr - erstmal geht es um die <strong>Konfiguration des RTE</strong>. Es ist unglaublich wie viele verschiedene Ansätze es dazu gibt, wie weit sich die Konfiguration verschachteln lässt und wie unglaublich nervig das werden kann.</p>
<p>Aber ich habe einige Ansätze gefunden die funktionieren.<br />
<span id="more-54"></span></p>
<h2>TSConfig erweitern</h2>
<p>Normalerweise definieren wir den <strong>RTE</strong> über das TSConfig Feld der Root Seite. Da der Benutzer der Extension dies aber nicht tun soll, erledigen wir das über die <strong>ext_localconf.php</strong> unserer Extension.</p>
<p>Hier ist es Möglich eine Variable, z.B. $rte_config, dem TSConfig hinzufügen:</p>
<pre><code class="php">t3lib_extMgm::addPageTSConfig($rte_config);</code></pre>
<p>In meinem konkreten Fall habe ich ein weiteres Tag definiert, <em>hivar</em>, welches ich gesondert formatieren möchte. Zur Lösung führte dann endlich folgendes:</p>
<pre>RTE.default {
  ignoreMainStyleOverride = 0
  mainStyleOverride = hivar { color:darkred; usw. usf. }
}</pre>
<p>Hinter <strong>mainStyleOverride</strong> kann man natürlich alles mögliche packen, besonders wichtig ist die zweite Zeile. Ansonsten zeigt es keine Wirkung, egal was man tut!</p>
<h2>Grafiken über CSS im RTE</h2>
<p>Möchte man <strong>per CSS Grafiken einbinden</strong>, muss man zwei Ebenen nach oben wechseln um im Rootverzeichnis des Projektes zu landen. Von hieraus am besten straight zur eigenen Extension:</p>
<pre><code class="css">background-image:url(../../typo3conf/ext/hivars/ext_icon.gif)</code></pre>
<h2>Eigene Tags hinzufügen</h2>
<p>Besonders angenehm ist auch die relativ neue Funktion <strong>addToList</strong>, womit ein komplettes überschreiben der vorhandenen Einstellung vermieden wird:</p>
<pre>allowTags:=addToList(hivar)</pre>
<h2>Ausblick</h2>
<p>Demnächst, oder in dringenden Fällen auf Anfrage, gibt es die gesamte RTE Konfiguration. Davor muss ich noch einige Dinge erweitern, vervollständigen und die Wechselwirkungen mit vorhanden Einstellungen untersuchen. Zum Glück haben wir einige Projekte in denen ich testen kann und die verwirrten Redakteure beobachten wenn irgendwas nicht mehr funktioniert.</p>
<p>Hoffentlich bleibt es nicht für immer so warm...</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2008/07/28/aus-der-mitte-entspringt-ein-rte/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress Plugin SpamKill!</title>
		<link>http://www.interaktionsdesigner.de/2008/07/09/wordpress-plugin-spamkill/</link>
		<comments>http://www.interaktionsdesigner.de/2008/07/09/wordpress-plugin-spamkill/#comments</comments>
		<pubDate>Wed, 09 Jul 2008 17:03:06 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=45</guid>
		<description><![CDATA[Na, genervt vom Spam in den Kommentaren? Meine Erfahrungen mit den fiesen Spamrobotern habe ich jetzt in ein WordPress Plugin gepackt und biete es zum freien Einsatz an. Hier auf dem Blog ist es schon im Einsatz, hat aber bisher noch nichts abwehren müssen. Direkt zum Download. Funktionsweise Die ausführliche Beschreibung finden Sie hier. Die [...]]]></description>
			<content:encoded><![CDATA[<p>Na, genervt vom Spam in den Kommentaren? Meine Erfahrungen mit den fiesen Spamrobotern habe ich jetzt in ein WordPress Plugin gepackt und biete es zum freien Einsatz an.<br />
Hier auf dem Blog ist es schon im Einsatz, hat aber bisher noch nichts abwehren müssen. <a href="http://www.interaktionsdesigner.de/2008/07/09/wordpress-plugin-spamkill/#download">Direkt zum Download</a>.</p>
<p><span id="more-45"></span></p>
<h2>Funktionsweise</h2>
<p><a href="http://www.interaktionsdesigner.de/2008/05/14/spamschutz-ohne-kompromisse/" target="_new">Die ausführliche Beschreibung finden Sie hier.</a> Die Regeln habe ich weiter vereinfacht. Mein PlugIn prüft aktuell nur 3 von 5:</p>
<ol>
<li><strong>Zeit</strong><br />
Ein Kommentator muss mind. 5s benötigen um einen Kommentar zu schreiben. Ansonsten ist er eine Machine.</li>
<li><strong>Vertauschte Bezeichnungen</strong><br />
Im HTML Formular sind Name und Emailfeld von den Bezeichnungen her vertauscht. Ist eine E-Mailadresse im Namenfeld eingetragen, handelt es sich mit ziemlicher Sicherheit um unerwünschte Werbung.</li>
<li><strong>Hiddenfield</strong><br />
Ein verstecktes Formularfeld (&lt;input type="hidden") muss leer bleiben. Spamroboter füllen meistens sinnlos alles aus.</li>
</ol>
<p>Schon wenn eine der Regeln zutritt wird der Kommentar abgewiesen.<br />
Zum verfolgen der Tätigkeiten wird eine simple Logdatei beschrieben. Dieses Verhalten sollte man bei vielen Spamnachrichten abschalten.</p>
<h2>Installation</h2>
<p>Nach dem Download in den Ordner <em>wp-content/plugins/</em> verschieben und im WordPress Backend aktivieren.</p>
<p>Anschließend müssen noch ein paar Dinge im Formular der Kommentareingabe angepasst werden. Je nach Theme unterschiedlich, meistens findet sich dies aber in der Datei <em>wp-content/themes/THEME-NAME/comments.php</em>.</p>
<ol>
<li><strong>Attribut Action vom Form-Tag</strong>
<p>Ich habe keinen anderen Weg gefunden in die Abarbeitung einzugreifen. Deshalb habe ich sie ersetzt. Das Attribut Action muss auf folgende Datei zeigen:</p>
<pre>&lt;?php echo get_option('siteurl'); ?&gt;/wp-content/plugins/id-spamkill/id-comments-without-spam.php</pre>
</li>
<li><strong>Bezeichnungen vertauschen</strong>
<p>Name und ID vom Namen und E-Mailfeld vertauschen. Nicht vergessen auch das for-Attribut vom Label anzupassen. Bei mir sieht es jetzt so aus:</p>
<pre><code class="html">&lt;p class="first"&gt;
	&lt;label for="email"&gt;Name &lt;?php if ($req) echo "(erforderlich)"; ?&gt;&lt;/label&gt;
	&lt;input class="styling" type="text" name="email" id="email" value="&lt;?php echo $comment_author; ?&gt;" size="22" tabindex="1" /&gt;
&lt;/p&gt;

&lt;p&gt;
	&lt;label for="author"&gt;eMail &lt;?php if ($req) echo "(erforderlich)"; ?&gt;&lt;/label&gt;
	&lt;input class="styling" type="text" name="author" id="author" value="&lt;?php echo $comment_author_email; ?&gt;" size="22" tabindex="2" /&gt;
	&lt;span&gt;(wird nicht veröffentlicht)&lt;/span&gt;
&lt;/p&gt;</code></pre>
</li>
<li>Innerhalb der beiden Form-Tags müssen die Hooks abgearbeitet werden. Auch das sollte bei den meisten Themes schon vorhanden sein:
<pre><code class="php">&lt;?php do_action('comment_form', $post-&gt;ID); ?&gt;</code></pre>
</li>
</ol>
<p>Zu guter letzt muss die Datei <em>wp-content/plugins/id-spamkill/id-spamlog.txt</em> für das Script noch beschreibbar gemacht werden (z.B. mit chmod(0777)). Das wars! Einträge werden gefiltert.</p>
<h2>Konfiguration</h2>
<p>Viel muss beim Plugin nicht konfiguriert werden. Da es so wenige Sachen sind sie noch nicht als "normale" Einstellungen über das Backend erreichbar sondern in der Datei <em>id-spamkill.php</em> zu finden. Ab Zeile 13 geht es los:</p>
<pre><code class="php">protected $logSpam = true;   // Spamlog speichern?
protected $logFile = "id-spamlog.txt";    // Datei in der das Spamlog gespeichert wird
protected $logSep = "\n-----------------------------------------------\n";    // Trennezeichen zwischen dein einzelnen Einträgen der Logdatei.</code></pre>
<h2 id="download">Download</h2>
<p>Das Plugin kann als <a href="http://www.interaktionsdesigner.de/wp-content/uploads/2008/07/id-spamkill-01.zip">Archiv herunter geladen werden</a>. Bei der Verwendung wäre eine kurze Nachricht nett.</p>
<h2>Fazit</h2>
<p>Das Plugin ist in einer sehr frühen Version und bietet noch viel Raum nach oben. Gerade die aufwendige Installation stört mich gewaltig, aber ich habe bisher keinen anderen Weg gefunden um so tiefgreifend das System zu verändern.</p>
<p>Ich habe ein gutes Gefühl und lade alle Besucher herzlich ein, mit mir zu beoachten welcher Spamkommentator es als erstes schafft durch zu kommen.</p>
<p>Bei Fragen, Problemen und Anregungen stehe ich gern zur Verfügung.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2008/07/09/wordpress-plugin-spamkill/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Save the Webdevelopers!</title>
		<link>http://www.interaktionsdesigner.de/2008/06/30/save-the-webdevelopers/</link>
		<comments>http://www.interaktionsdesigner.de/2008/06/30/save-the-webdevelopers/#comments</comments>
		<pubDate>Mon, 30 Jun 2008 13:56:26 +0000</pubDate>
		<dc:creator>Paul</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Entwicklung]]></category>

		<guid isPermaLink="false">http://www.interaktionsdesigner.de/?p=41</guid>
		<description><![CDATA[Heute war ein schöner Tag im Feedreader betreffs Browserkompalibilität. Im außergewöhnlich guten Blog WebAppers finden sich 10 lesenswerte Punkte die es bei der Programmierung zu beachten gibt. Besonders gefreut habe ich mich über den dritten Punkt: "Use -moz-opacity:0.99 on text elements to clean up rendering in Firefox". Gleich getestet und es stimmt: Mit dieser CSS [...]]]></description>
			<content:encoded><![CDATA[<p>Heute war ein schöner Tag im Feedreader betreffs Browserkompalibilität. Im außergewöhnlich guten Blog <a href="http://www.webappers.com/" target="_blank">WebAppers</a> finden sich <a href="http://www.webappers.com/2008/06/27/how-to-get-cross-browser-compatibility-every-time/" target="_blank">10 lesenswerte Punkte</a> die es bei der Programmierung zu beachten gibt.</p>
<p>Besonders gefreut habe ich mich über den dritten Punkt: "<em>Use -moz-opacity:0.99 on text elements to clean up rendering in Firefox</em>". Gleich getestet und es stimmt: Mit dieser CSS Angabe verhindert man das lästige zucken der Schrift bei JavaScript Effekten!</p>
<p>Insgesamt finde ich es aber falsch jedes Mal alle Schwächen vom IE6 auszubügeln. Den betreffenden Benutzern muss klar gemacht werden, dass sie alte und schlechte Software benutzen. Einen guten Weg geht die Initiative <a href="http://www.savethedevelopers.org/">SaveTheDevelopers.org</a>. Mit einem kleinen JavaScript werden die Besucher dezent auf den Umstand aufmerksam gemacht.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.interaktionsdesigner.de/2008/06/30/save-the-webdevelopers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

