<?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>leine.info &#187; JavaScript</title>
	<atom:link href="http://leine.info/category/javascript/feed/" rel="self" type="application/rss+xml" />
	<link>http://leine.info</link>
	<description>Discover my public and private World.</description>
	<lastBuildDate>Thu, 22 Dec 2011 13:57:16 +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>Grails UI, gui:dataTable und i18n</title>
		<link>http://leine.info/2011/12/grails-ui-guidatatable-und-i18n/</link>
		<comments>http://leine.info/2011/12/grails-ui-guidatatable-und-i18n/#comments</comments>
		<pubDate>Tue, 13 Dec 2011 11:02:31 +0000</pubDate>
		<dc:creator>jleine</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[dataTable]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[grails ui]]></category>
		<category><![CDATA[gui:dataTable]]></category>
		<category><![CDATA[i18n]]></category>
		<category><![CDATA[YUI]]></category>

		<guid isPermaLink="false">http:/leine.info//leine.info/ssl-account.com/leine.info/?p=418</guid>
		<description><![CDATA[Vor kurzem habe ich mich mit Grails beschäftigt. Eigentlich eine ziemlich nettes Framework, mit dem man schnell einen Prototyp programmieren kann. Für meinen Geschmack war die Unterstützung für Rich UI allerdings etwas dürftig, doch das ist kein Problem, denn in &#8230; <a href="http://leine.info/2011/12/grails-ui-guidatatable-und-i18n/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Vor kurzem habe ich mich mit <a href="http://grails.org/">Grails</a> beschäftigt. Eigentlich eine ziemlich nettes Framework, mit dem man schnell einen Prototyp programmieren kann. Für meinen Geschmack war die Unterstützung für Rich UI allerdings etwas dürftig, doch das ist kein Problem, denn in diese Lücke springen in Grails die sogenannten <a href="http://www.grails.org/plugins/">Plugins</a>.</p>
<p>In meinem Fall habe ich mich für das <a href="http://www.grails.org/plugin/grails-ui">Grails-UI Plugin</a> entschieden. Dieses Plugin bietet eine schöne Integration von <a href="http://developer.yahoo.com/yui/">YUI</a> und YUI wiederum bietet ein umfangreiches Set an Rich UI Komponenten.</p>
<p>Das Plugin war schnell installiert und die Integration in Grails war auch relativ leicht umzusetzen. Vor allem das Tag <strong>&lt;gui:dataTable&gt;</strong> kam bei mir stark zum Einsatz. Irgendwann allerdings kam ich zu dem Punkt, wo ich mich mit Internationalisierung auseinandersetzen musste und dieses Problem war leider nur sehr dürftig beschrieben. Aus diesem Grund will ich heute kurz aufzeigen was man hierfür alles tun muss.</p>
<p><span id="more-418"></span></p>
<h2>i18n für YUI</h2>
<p>Um YUI zu internationalisieren muss man ein wenig in der offiziellen Doku suchen. Leider habe ich kein durchgängiges Konzept erkennen können. Teilweise müssen einfach statische JS Variablen umdefiniert werden, teilweise muss eine Variable im prototype überschrieben werden und teilweise müssen sog. Data Formatter definiert werden, die z.B. eine Datumszelle entsprechend formatieren.</p>
<pre name="code" class="javascript">  YAHOO.widget.Calendar.DEFAULT_CONFIG.NAV.value = true;
  YAHOO.widget.Calendar.DEFAULT_CONFIG.CLOSE.value = "Schlie\u00DFen"

  // Correct formats for Germany: dd.mm.yyyy, dd.mm, mm.yyyy
  YAHOO.widget.Calendar.DEFAULT_CONFIG.DATE_FIELD_DELIMITER.value = ".";

  YAHOO.widget.Calendar.DEFAULT_CONFIG.MDY_DAY_POSITION.value = 1;
  YAHOO.widget.Calendar.DEFAULT_CONFIG.MDY_MONTH_POSITION.value = 2;
  YAHOO.widget.Calendar.DEFAULT_CONFIG.MDY_YEAR_POSITION.value = 3;

  YAHOO.widget.Calendar.DEFAULT_CONFIG.MD_DAY_POSITION.value = 1;
  YAHOO.widget.Calendar.DEFAULT_CONFIG.MD_MONTH_POSITION.value = 2;

  // Date labels for German locale
  YAHOO.widget.Calendar.DEFAULT_CONFIG.MONTHS_SHORT.value = ["Jan", "Feb", "M\u00E4r", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"];
  YAHOO.widget.Calendar.DEFAULT_CONFIG.MONTHS_LONG.value = ["Januar", "Februar", "M\u00E4rz", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"];
  YAHOO.widget.Calendar.DEFAULT_CONFIG.WEEKDAYS_1CHAR.value = ["S", "M", "D", "M", "D", "F", "S"];
  YAHOO.widget.Calendar.DEFAULT_CONFIG.WEEKDAYS_SHORT.value = ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"];
  YAHOO.widget.Calendar.DEFAULT_CONFIG.WEEKDAYS_MEDIUM.value = ["Son", "Mon", "Die", "Mit", "Don", "Fre", "Sam"];
  YAHOO.widget.Calendar.DEFAULT_CONFIG.WEEKDAYS_LONG.value = ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"];

  // Start the week on a Monday (Sunday == 0)
  YAHOO.widget.Calendar.DEFAULT_CONFIG.START_WEEKDAY.value = 1;

  //CalendarNavigator show up if clicked on the current month
  YAHOO.widget.CalendarNavigator.DEFAULT_CONFIG.strings.submit = "OK"
  YAHOO.widget.CalendarNavigator.DEFAULT_CONFIG.strings.cancel = "Abbr."
  YAHOO.widget.CalendarNavigator.DEFAULT_CONFIG.strings.invalidYear = "Das Jahr muss eine Zahl sein."
  YAHOO.widget.CalendarNavigator.DEFAULT_CONFIG.strings.month = "Monat"
  YAHOO.widget.CalendarNavigator.DEFAULT_CONFIG.strings.year = "Jahr"

    YAHOO.widget.BaseCellEditor.prototype.LABEL_SAVE = "OK"
    YAHOO.widget.BaseCellEditor.prototype.LABEL_CANCEL = "Abbr."

    /*
     * BUGFIX for YUI &lt; 2.9
     * If a date cell contains a null value the cell editor calendar does not show up.
     * Till we're not using YUI 2.9 and above this is the fix for it.
     *
     * http://yuilibrary.com/projects/yui2/ticket/2529117
     */
    YAHOO.widget.DateCellEditor.prototype.resetForm = function() {
      var value = this.value || new Date();
      var selectedValue = (value.getMonth()+1)+"/"+value.getDate()+"/"+value.getFullYear();
      this.calendar.cfg.setProperty("selected",selectedValue,false);
      this.calendar.render();
    };

    YAHOO.widget.DataTable.Formatter.date = function(elCell, oRecord, oColumn, oData) {
      var oDate = oData;
      if(oDate instanceof Date) {
        elCell.innerHTML = YAHOO.util.Date.format(oDate, { format: "%d.%m.%Y"});
      } else {
        elCell.innerHTML = '';
      }
    };</pre>
<p>Damit hat man zumindest den reinen YUI DataTable umgestellt. Der große Teil ist hier einfach die Übersetzung der englischen Strings in die jeweilige Zielsprache. Ein kleinerer Teil ist die Verwendung eines speziellen DateFormatters, damit in der Zelle selbst ein deutsches Format verwendet wird, und zum Schluss noch ein Bugfix für YUI selbst, denn das Grails Plugin verwendet momentan noch YUI in der Version 2.8. In dieser Version ist es unmöglich für eine leere Datums Tabellenzelle einen neuen Wert zu definieren. Sollte das Grails Plugin irgendwann YUI die Version 2.9 verwenden entfällt dieser Bugfix.</p>
<h2>i18n für Grails</h2>
<p>Hat man YUI nun eine andere Sprache beigebracht, muss man sich jetzt noch um den Grails Teil kümmern. Folgender Template Code demonstriert dies kurz.</p>
<pre name="code" class="html">        &lt;!-- http://jira.grails.org/browse/GPUI-250 --&gt;
        &lt;g:set var="i18nfirstName" value="${message(code: 'user.firstName.label', default: 'First Name')}"/&gt;
        &lt;g:set var="i18nlastName" value="${message(code: 'user.lastName.label', default: 'Last Name')}" /&gt;
        &lt;g:set var="i18ndate" value="${message(code: 'user.date.label', default: 'Date')}" /&gt;

        &lt;g:set var="i18nfirstPage" value="${message(code: 'disy.paginator.firstPage.label', default: 'First Page')}" /&gt;
        &lt;g:set var="i18npreviousPage" value="${message(code: 'disy.paginator.previousPage.label', default: 'Previous Page')}" /&gt;
        &lt;g:set var="i18nnextPage" value="${message(code: 'disy.paginator.nextPage.label', default: 'Next Page')}" /&gt;
        &lt;g:set var="i18nlastPage" value="${message(code: 'disy.paginator.lastPage.label', default: 'Last Page')}" /&gt;

        &lt;gui:dataTable
          id="myList"
          selectionMode="standard"
          draggableColumns="true"
          sortedBy="lastName"
          columnDefs="[
                  [id:'Id',
                   hidden: true ],

                  [lastName: i18nlastName,
                   formatter:  'text' ,
                   editor:[controller:'myController', action:'tableChange', onSuccess:'successCallback', onFailure:'failureCallback'],
                   sortable:true,
                   resizeable: true],

                  [firstName: i18nfirstName,
                   formatter:  'text' ,
                   editor:[controller:'myController', action:'tableChange', onSuccess:'successCallback', onFailure:'failureCallback'],
                   sortable:true,
                   resizeable: true],

                  [date: i18ndate,
                   formatter:  'date',
                   editor:[controller:'myController', action:'tableChange', onSuccess:'successCallback', onFailure:'failureCallback'],
                   sortable:true,
                   resizeable: true]]"
          allowExclusiveSort='true'
          controller="myController" action="listJSON"
          rowsPerPage="30"
          MSG_EMPTY="${message(code: 'dataTable.empty.label', default: 'No records found.')}"
          MSG_ERROR="${message(code: 'dataTable.error.label', default: 'Data error.')}"
          MSG_LOADING="${message(code: 'dataTable.loading.label', default: 'Loading...')}"
          paginatorConfig="[
            firstPageLinkLabel: '&amp;lt;&amp;lt;',
            firstPageLinkTitle: i18nfirstPage,
            previousPageLinkLabel: '&amp;lt;',
            previousPageLinkTitle: i18npreviousPage,
            nextPageLinkLabel: '&amp;gt;',
            nextPageLinkTitle: i18nnextPage,
            lastPageLinkLabel: '&amp;gt;&amp;gt;',
            lastPageLinkTitle: i18nlastPage
          ]" /&gt;</pre>
<p>HIerbei fällt folgendes auf:</p>
<ul>
<li>Der Pager wird als paginatorConfig umdefiniert, damit dieser auch in der gewünschten Zielsprache ist.</li>
<li>Die Default Texte für einen leeren DataTable (MSG_EMPTY, MSG_ERROR, MSG_LOADING) werden ebenfalls definiert.</li>
<li>Alle Zellenüberschriften werden zuvor als Grails Variable angelegt und verwendet. Dies ist leider noch ein Feature Request für gui:dataTable und vielleicht wird dies in absehbarer Zeit umgesetzt.</li>
</ul>
<p>Damit hat man nun einen DataTable, der fast fertig ist. Fast deswegen, weil die übermittelten Werte des YUI DataTable auf Controller Seite noch formatiert werden müssen. Werden neue Datumswerte ausgewählt, dann überträgt YUI dies in einem bestimmten DateFormat, welches wir auf Grails Seite bei einem AJAX Update entsprechend in unser Date parsen müssen.</p>
<pre name="code" class="Java">    //Parse param
    if (params.field == 'date') {
      SimpleDateFormat formatter = new java.text.SimpleDateFormat("E MMM dd yyyy HH:mm:ss ZZZZZZZ", Locale.ROOT);
      myObject."$params.field" = formatter.fomrmat(params.newValue)
    }</pre>
<p>Haben wir all diese Schritte entsprechend umgesetzt, sollten wir nun in der Lage sein einen internationalisierten gui:dataTable zu verwenden.</p>
]]></content:encoded>
			<wfw:commentRss>http://leine.info/2011/12/grails-ui-guidatatable-und-i18n/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mein Linux läuft im Browser</title>
		<link>http://leine.info/2011/05/mein-linux-lauft-im-browser/</link>
		<comments>http://leine.info/2011/05/mein-linux-lauft-im-browser/#comments</comments>
		<pubDate>Fri, 20 May 2011 07:37:30 +0000</pubDate>
		<dc:creator>jleine</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://leine.info/?p=375</guid>
		<description><![CDATA[Der derzeitige Trend geht immer mehr in Richtung Internet. So brachte vor kurzem z.B. Google sein Chrome OS heraus, um so den Endanwender in ein paar Sekunden den Zugriff auf das Internet zu ermöglichen. Softwareprodukte installieren? Fehlanzeige. Alles ist schon &#8230; <a href="http://leine.info/2011/05/mein-linux-lauft-im-browser/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Der derzeitige Trend geht immer mehr in Richtung Internet. So brachte vor kurzem z.B. Google sein <a href="http://www.google.com/chromebook/#features">Chrome OS</a> heraus, um so den Endanwender in ein paar Sekunden den Zugriff auf das Internet zu ermöglichen. Softwareprodukte installieren? Fehlanzeige. Alles ist schon installiert, denn alles liegt im Internet und muss gar nicht mehr installiert werden.</p>
<p>Solche Anwendungen setzen immer mehr moderne Browser voraus und das alles wäre ohne den intensiven Einsatz von JavaScript gar nicht erst möglich.</p>
<p>Das JavaScript immer leistungsfähiger wird demonstriert nun das Projekt von <a href="http://bellard.org/">Fabrice Bellard</a>. Seit der Einführung von Typed Arrays in JavaScript wird einem nicht nur  typsichere Programmierung erleichtert, sondern sie ermöglicht auch die Emulation eines Prozessors. Dies wird eindrucksvoll mit dem Projekt <a href="http://bellard.org/jslinux/">JSLinux</a> demonstriert. Bellard stellt eine x86-kompatible 32-Bit-CPU, einen Interrupt Controller, Interrupt Timer und eine serielle Schnittstelle in gut 90 KByte bereit. Das wiederum dient als Basis um, zugegeben auf Basis eines etwas veralteten Linux Kernel, ein komplettes Betriebssystem im Browser laufen zu lassen. Allen JavaScript Skeptikern oder Linux Neulingen empfehle ich hiermit dieses OS einmal dringend auszuprobieren.</p>
<p>Eine Anmerkung noch zum Schluss. JSLinux hat dann doch eine kleine Voraussetzung. Der Einsatz von TypedArrays setzt leider einen aktuellen Browser voraus. Momentan läuft <a href="http://bellard.org/jslinux/">JSLinux</a> nur unter <a href="www.mozilla.com/firefox/fx/">Firefox 4</a> und <a href="www.google.com/chrome/">Chrome 11</a>. Solltet ihr dem nicht entsprechen könnt ihr euren Ausflug auch gleich mit der Installation eines modernen Browsers verbinden.</p>
]]></content:encoded>
			<wfw:commentRss>http://leine.info/2011/05/mein-linux-lauft-im-browser/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JAXB für JavaScript &#8211; oder wie parse ich XML in JSON</title>
		<link>http://leine.info/2011/04/jaxb-fur-javascript-oder-wie-parse-ich-xml-in-json/</link>
		<comments>http://leine.info/2011/04/jaxb-fur-javascript-oder-wie-parse-ich-xml-in-json/#comments</comments>
		<pubDate>Fri, 29 Apr 2011 07:00:37 +0000</pubDate>
		<dc:creator>jleine</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[JAXB]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[Jsonix]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://leine.info/?p=364</guid>
		<description><![CDATA[Denkt man an XML Parsing in JAVA denkt man zuerst an JAXB. JAXB ist eine komfortable Methode XML in JAVA zu parsen. Man gibt dem Marshaller einfach ein XML File zum lesen und am Ende erhält man normale Java Instanzen, &#8230; <a href="http://leine.info/2011/04/jaxb-fur-javascript-oder-wie-parse-ich-xml-in-json/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Denkt man an XML Parsing in JAVA denkt man zuerst an <a href="http://jaxb.java.net/">JAXB</a>. JAXB ist eine komfortable Methode XML in JAVA zu parsen. Man gibt dem Marshaller einfach ein XML File zum lesen und am Ende erhält man normale Java Instanzen, die das eingelesene XML File wiedergeben. Eine wirklich einfache und komfortable Lösung.<span id="more-364"></span></p>
<p>Ganz anders sieht es allerdings aus wenn man das gleiche in JavaScript machen will. JAXB gibt es für JavaScript leider nicht und das parsen von XML in JavaScript ist leider auch nicht wirklich komfortabel. Auch wenn JSON mehr und mehr auf dem Vormarsch ist, kommt man teilweise doch nicht drum herum XML zu verarbeiten. Wie schön wäre es da, wenn man die gleichen komfortablen Mechanismen wie in Java hätte.</p>
<p>Nun, die gibt es. Auf meine Streifzügen durchs Web bin ich heute auf das Projekt <a href="http://confluence.highsource.org/display/JSNX/Jsonix">Jsonix</a> gestoßen. Dieses Projekt orientiert sich eindeutig am JAXB Paradigma. Es bietet einem die gleichen komfortablen Mechanismen und es nimmt einem die lästige Arbeit ab XML in JavaScript Objekte zu wandeln.</p>
<p>Kleiner Vorgeschmack gefällig?</p>
<p>Mal angenommen wir wollen folgendes XML File in JavaScript einlesen und in JSON verwandeln.</p>
<pre name="code" class="xml">
<purchaseOrder orderDate="1999-10-20">
  <shipTo country="US">
    <name>Alice Smith</name>
    <street>123 Maple Street</street>
    <city>Mill Valley</city>
    <state>CA</state>
    <zip>90952</zip>
  </shipTo>
  <billTo country="US">
    <name>Robert Smith</name>
    <street>8 Oak Avenue</street>
    <city>Old Town</city>
    <state>PA</state>
    <zip>95819</zip>
  </billTo>
  <comment>Hurry, my lawn is going wild!</comment>
  <items>
    <item partNum="872-AA">
<productName>Lawnmower</productName>
      <quantity>1</quantity>
      <USPrice>148.95</USPrice>
      <comment>Confirm this is electric</comment>
    </item>
    <item partNum="926-AA">
<productName>Baby Monitor</productName>
      <quantity>1</quantity>
      <USPrice>39.98</USPrice>
      <shipDate>1999-05-21</shipDate>
    </item>
  </items>
</purchaseOrder>
</pre>
<p>Um dieses XML File einzulesen müssen wir in Jsonix folgende Zeilen Code schreiben.</p>
<pre name="code" class="javascript">
var PO = { };
var context = new Jsonix.Context([ PO ]);
var unmarshaller = context.createUnmarshaller();
unmarshaller.unmarshalURL('/org/hisrc/jsonix/samples/po/test/po-0.xml',
  function(result) {
    assertEquals('Alice Smith', result.value.shipTo.name);
    assertEquals('Baby Monitor', result.value.item[1].productName);
  }
);
</pre>
<p>Sieht gut aus? Stimmt! Der geneigte JAXB User erkennt deutlich die Parallelen. Meiner Meinung nach ist dies eine deutliche Erleichterung um XML mit JavaScript einzulesen. <a href="http://confluence.highsource.org/display/JSNX/Jsonix">Jsonix</a> hat auf jeden Fall meine Aufmerksamkeit verdient.</p>
]]></content:encoded>
			<wfw:commentRss>http://leine.info/2011/04/jaxb-fur-javascript-oder-wie-parse-ich-xml-in-json/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaScript Garden</title>
		<link>http://leine.info/2011/03/javascript-garden/</link>
		<comments>http://leine.info/2011/03/javascript-garden/#comments</comments>
		<pubDate>Sat, 12 Mar 2011 19:00:24 +0000</pubDate>
		<dc:creator>jleine</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://leine.info/?p=360</guid>
		<description><![CDATA[Heute bin ich im Web auf die Seite JavaScript Garden gestoßen. Diese Seite richtet sich an JavaScript Entwickler, die nicht andauernd die Einführung in Script Sprachen lesen wollen. Die Autoren wollen eher eine Sammlung an kleinen Expertentipps liefern, damit häufig &#8230; <a href="http://leine.info/2011/03/javascript-garden/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Heute bin ich im Web auf die Seite <a href="http://bonsaiden.github.com/JavaScript-Garden/">JavaScript Garden</a> gestoßen. Diese Seite richtet sich an JavaScript Entwickler, die nicht andauernd die Einführung in Script Sprachen lesen wollen. Die Autoren wollen eher eine Sammlung an kleinen Expertentipps liefern, damit häufig gemachte Fehler vermieden werden. Mein erster Eindruck war überaus positiv und ich kann jedem geneigten JS Entwickler nur empfehlen ebenfalls einen Blick darauf zu werfen.</p>
]]></content:encoded>
			<wfw:commentRss>http://leine.info/2011/03/javascript-garden/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Javascript Deminifier</title>
		<link>http://leine.info/2011/03/javascript-deminifier/</link>
		<comments>http://leine.info/2011/03/javascript-deminifier/#comments</comments>
		<pubDate>Wed, 09 Mar 2011 18:00:25 +0000</pubDate>
		<dc:creator>jleine</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Firebug]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[YuiCompressor]]></category>

		<guid isPermaLink="false">http://leine.info/?p=345</guid>
		<description><![CDATA[Immer wieder stolpert man über eine tolle Seite, die schöne Effekte beinhaltet oder einfach nur cool aufgemacht ist. Oftmals stelle ich mir dann die Frage: Wie machen die das nur? Nichts leichter als das. Firebug anwerfen und HTML Code lesen. &#8230; <a href="http://leine.info/2011/03/javascript-deminifier/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Immer wieder stolpert man über eine tolle Seite, die schöne Effekte beinhaltet oder einfach nur cool aufgemacht ist. Oftmals stelle ich mir dann die Frage: Wie machen die das nur? <span id="more-345"></span></p>
<p>Nichts leichter als das. <a href="https://addons.mozilla.org/de/firefox/addon/firebug/">Firebug</a> anwerfen und HTML Code lesen. Jedoch stößt man schnell an seine Grenzen, denn es gibt heutzutage nur noch sehr wenige Webseiten, die ohne JavaScript Code auskommen. Auch kein Problem, denkt sich der geneigte Webentwickler und wirft schnell einen Blick auf den Script Tab von Firebug. Nur dumm, daß der ausgelieferte JavaScript Code komprimiert ausgeliefert wird und damit meine ich jetzt nicht gzip, sondern tatsächlich komprimiert. Warum? Nun, viele Seiten und Frameworks verwenden meist ein Build Tool, welches einmalig alle einzelnen JavaScript Dateien in eine Datei packt. So wird aus tausend kleinen JS Dateien eine große. Doch damit nicht genug, denn meistens werden anschließend auch noch alle Formatierungen über Board geworfen. Eine große JS Datei kann man zumindest teilweise verstehen, doch ohne Codeformatierung geht meistens nichts mehr. Mal eben einen Breakpoint in Firebug setzen und durch fremden JS Code durchdebuggen wenn der gesamte Code in einer einzigen Zeile steht? Keine Chance!</p>
<p>Doch das muss nicht sein. Heute bin ich über ein kleines Firefox Add-On gestoßen, welches diesem Umstand endlich ein Ende setzt. Es nennt sich <a href="https://addons.mozilla.org/de/firefox/addon/javascript-deminifier/">JavaScript Deminifier</a>. Einmal installiert muss man es lediglich nur noch auf der gewünschten Seite aktivieren und endlich kann man den JS Code lesen, verstehen und nachvollziehen. Schön das die meisten Webseiten nur diese Art der Code Obfuscation nutzen. Endlich kann man sich wieder die ein oder andere Idee holen.</p>
<p>In diesem Sinne viel Spaß beim Fremd-Code studieren ;)</p>
]]></content:encoded>
			<wfw:commentRss>http://leine.info/2011/03/javascript-deminifier/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>File API, oder wie lade ich Dateien demnächst hoch</title>
		<link>http://leine.info/2009/11/file-api-oder-wie-lade-ich-dateien-demnachst-hoch/</link>
		<comments>http://leine.info/2009/11/file-api-oder-wie-lade-ich-dateien-demnachst-hoch/#comments</comments>
		<pubDate>Fri, 27 Nov 2009 08:59:59 +0000</pubDate>
		<dc:creator>jleine</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[File API]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[W3C]]></category>

		<guid isPermaLink="false">http://leine.info/?p=320</guid>
		<description><![CDATA[Heute musste ich erfahren das Firefox in seiner vierten Beta Version 3.6 die File API integriert hat. Damit wird es uns Webentwicklern demnächst deutlich erleichtert File Uploads anzubieten. Die JS API bietet dabei alles was man sich so wünscht. Ein &#8230; <a href="http://leine.info/2009/11/file-api-oder-wie-lade-ich-dateien-demnachst-hoch/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Heute musste ich erfahren das <a href="http://www.mozilla.com/en-US/firefox/3.6b4/releasenotes/">Firefox in seiner vierten Beta Version 3.6</a> die File API integriert hat. Damit wird es uns Webentwicklern demnächst deutlich erleichtert File Uploads anzubieten. Die JS API bietet dabei alles was man sich so wünscht. Ein File Object was einem Methoden für den Filenamen, den File-Mime-Type und  die File-Größe bietet. Einen vereinfachten Drag und Drop Modus um Dateien hochzuladen und eine Möglichkeit kleine Vorschaubilder der Datei direkt im Browser zu erstellen.<br />
Wer sich vorab schon mit ein paar Code Beispielen beschäftigen will dem kann ich einen Blick ins <a href="https://developer.mozilla.org/en/Using_files_from_web_applications">Mozilla Developer Center</a> nur empfehlen. Ich für meinen Teil kann es kaum erwarten. Die Grenze zwischen Desktop und Web verwischt immer mehr :-)</p>
]]></content:encoded>
			<wfw:commentRss>http://leine.info/2009/11/file-api-oder-wie-lade-ich-dateien-demnachst-hoch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hacking t:tree2, oder wie klappe ich Subnodes bei einem onclick auf?</title>
		<link>http://leine.info/2009/02/hacking-ttree2-oder-wie-klappe-ich-subnodes-bei-einem-onclick-auf/</link>
		<comments>http://leine.info/2009/02/hacking-ttree2-oder-wie-klappe-ich-subnodes-bei-einem-onclick-auf/#comments</comments>
		<pubDate>Fri, 13 Feb 2009 09:48:36 +0000</pubDate>
		<dc:creator>jleine</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[JSF]]></category>
		<category><![CDATA[Prototype]]></category>
		<category><![CDATA[Tomahawk]]></category>

		<guid isPermaLink="false">http://leine.info/?p=139</guid>
		<description><![CDATA[Neulich stand ich vor einem trivialen Problem der Tomahawk Tree Komponente. Bei einem onclick event auf einen Ordner sollten sich die jeweiligen Subnodes öffnen. Also nahm ich, in meinen jugendlichen Leichtsinn, an, daß dies nur eine Konfigurationsoption der t:tree2 Komponente &#8230; <a href="http://leine.info/2009/02/hacking-ttree2-oder-wie-klappe-ich-subnodes-bei-einem-onclick-auf/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Neulich stand ich vor einem trivialen Problem der Tomahawk Tree Komponente. Bei einem onclick event auf einen Ordner sollten sich die jeweiligen Subnodes öffnen. Also nahm ich, in meinen jugendlichen Leichtsinn, an, daß dies nur eine Konfigurationsoption der t:tree2 Komponente sein kann. Doch leider wurde ich in der <a href="http://www.jsftoolbox.com/documentation/tomahawk/09-TagReference/tomahawk-tree2.html">Tagreferenz</a> von Tomahawk nicht fündig. Wäre die tree Komponente von <a href="http://livedemo.exadel.com/richfaces-demo/richfaces/tree.jsf?tab=info&amp;cid=584054">Richfaces</a> gewesen, wäre dies kein Problem gewesen, denn hier gibt es die Option toggleOnClick.<span id="more-139"></span></p>
<p>[code lang='xhtml']<rich:tree switchType="ajax" toggleOnClick="true"<br />
    value="#{richNavigatorBean.treeNode}" var="node">[/code]</p>
<p>Doch zurück zum eigentlichen Problem. Ein genauerer Blick in den von Tomahawk generierten Quellcode brachte mich auf eine Idee.<br />
[code lang='xhtml']<br />
<img id="_idJsp15:navigator:0:1:1:t2" style="cursor: pointer;" onclick="treeNavClick('org.apache.myfaces.tree.TOGGLE_SPAN:_idJsp15:navigator:0:1:1:0:1:1', '_idJsp15:navigator:0:1:1:t2', '/brs-web/faces/myFacesExtensionResource/org.apache.myfaces.renderkit.html.util.MyFacesResourceLoader/12345174/tree2.HtmlTreeRenderer/images/nav-plus.gif', '/brs-web/faces/myFacesExtensionResource/org.apache.myfaces.renderkit.html.util.MyFacesResourceLoader/12345174/tree2.HtmlTreeRenderer/images/nav-minus.gif', '_idJsp15:navigator:0:1:1:t2c', '/brs-web/themes/anonymous/images/tree/folder_open_new.gif', '/brs-web/themes/anonymous/images/tree/folder_close_new.gif', 'navigator', '0:1:1');" src="/brs-web/faces/myFacesExtensionResource/org.apache.myfaces.renderkit.html.util.MyFacesResourceLoader/12345174/tree2.HtmlTreeRenderer/images/nav-plus.gif" border="0" alt="" width="19" height="18" />[/code]<br />
Wie man unschwer erkennt rendert Tomahawk in alle Images zum auf- und zuklappen ein onclick event, welches die treeNavClick Funktion triggert. Die Idee besteht nun darin, daß bei einem onclick auf den Ordner oder dessen Beschriftung eben jene treeNavClick Funktion getriggert wird. Dies ist, wenn man sich in <a href="http://www.prototypejs.org/">Prototype</a> ein wenig auskennt, kein Problem.</p>
<p>Zuerst passen wir das Rendering der t:tree2 Koponente ein wenig an.<br />
[code lang='xhtml']<br />
      <t:tree2 id="navigator" value="#{navigatorBean.navigator}"<br />
        binding="#{navigatorBean.newTree}" var="node"><br />
        <f:facet name="folder"><br />
          <h:panelGroup id="folderPanelGroup"><br />
            <f:facet name="expand"><br />
              <t:graphicImage<br />
                value="#{contextPath}/#{themePath}/images/tree/folder_open_new.gif"<br />
                rendered="#{toggler.nodeExpanded}" styleClass="folderIcon" onclick="treeNavigatorExpand($(this));" /><br />
            </f:facet><br />
            <f:facet name="collapse"><br />
              <t:graphicImage<br />
                value="#{contextPath}/#{themePath}/images/tree/folder_close_new.gif"<br />
                rendered="#{!toggler.nodeExpanded}" styleClass="folderIcon" onclick="treeNavigatorExpand($(this));" /><br />
            </f:facet><br />
              <h:outputText value="#{node.description}" styleClass="folderName" onclick="treeNavigatorExpand($(this));" /><br />
          </h:panelGroup><br />
        </f:facet><br />
        ...<br />
[/code]<br />
Rendert Tomahawk jetzt die Koponente erneut haben wir nun für alle Folder und dessen Beschriftung onclick events definiert. Diese events triggern die JS Funktion treeNavigatorExpand(this), welche folgendermaßen aufgebaut ist:<br />
[code lang='javascript']<br />
function treeNavigatorExpand(element){<br />
   element.up(1).select('img[onclick]')[0].onclick();<br />
}<br />
[/code]</p>
<p>Und fertig ist der Hack.</p>
<p>Nun wie funktioniert dieser? Ganz einfach. Bei einem onclick event auf den Folder oder dessen Beschriftung springen wir im DOM zwei parents nach oben, was bedeutet das wir uns in der aktuellen Tabellenzeile befinden (tr). Nun suchen wir ab dieser Zeile alle Images, die ein onclick event haben und verwenden dort das erste Element. Dieses Element ist eben besagtes auf- und zuklapp Icon von Tomahawk und dieses definiert die gewünschte treeNavClick Funktion, welche wir nur noch aufrufen müssen.</p>
<p>Zugegeben, das ist nicht die eleganteste Lösung, aber wie schon oben erwähnt, es ist ein Hack und ein Hack muss nicht immer elegant sein ;-)</p>
]]></content:encoded>
			<wfw:commentRss>http://leine.info/2009/02/hacking-ttree2-oder-wie-klappe-ich-subnodes-bei-einem-onclick-auf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Prototype und Frames</title>
		<link>http://leine.info/2009/01/prototype-und-frames/</link>
		<comments>http://leine.info/2009/01/prototype-und-frames/#comments</comments>
		<pubDate>Tue, 27 Jan 2009 09:04:54 +0000</pubDate>
		<dc:creator>jleine</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Frames]]></category>
		<category><![CDATA[Prototype]]></category>

		<guid isPermaLink="false">http://leine.info/?p=81</guid>
		<description><![CDATA[Da ich Framesets in der Regel verabscheue und meine Kenntnisse etwas eingestaubt sind, stand ich neulich vor dem trivialen Problem mit Hilfe von Prototype auf ein DOM Element in einem anderen Frame zuzugreifen. Wenn man nämlich den Frame wechseln muss, &#8230; <a href="http://leine.info/2009/01/prototype-und-frames/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Da ich Framesets in der Regel verabscheue und meine Kenntnisse etwas eingestaubt sind, stand ich neulich vor dem trivialen Problem mit Hilfe von Prototype auf ein DOM Element in einem anderen Frame zuzugreifen. Wenn man nämlich den Frame wechseln muss, dann hilft einem die magic knife Funktion $(DOMElement) nicht wirklich weiter, da in diesem Falle nur im DOM des aktuellen Frames gesucht wird. Die einfachste Variante wäre in diesem Falle, den Namen des Frames voranzustellen, also z.B. so: frameName.$(DOMElement). <span id="more-81"></span></p>
<p>Doch was ist, wenn man nun ein allgemeine Funktion schreiben will, in der der Name des Frames dynamisch übergeben wird? In diesem Fall kann man die einfache Notation von oben nicht verwenden.</p>
<p>Ein kurzer Blick in meine JavaScript Bibel, <a href="http://www.amazon.de/JavaScript-The-Definitive-Guide/dp/0596101996">JavaScript the Definitive Guide</a>, brachte dann die Erkenntnis. Zuerst einmal geht man einfach davon aus, dass man zur Laufzeit sich in einem Frame befindet. Sollte der Frame gewechselt werden, greift man zunächst auf parent, also das FrameSet zu. Von dort aus können wir mit der $(domElement) Funktion auf das gewollte Frame zugreifen, voraussgesetzt es verwendet eine id.</p>
<p>[code lang='xhtml']<br />
<frameset rows="100,*"><br />
  <frame name="topFrame" id="topFrame" src="top.html" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" noresize="noresize" ><br />
  <frameset cols="250,*"><br />
      <frame name="leftFrame" id="leftFrame" src="left.html" frameborder="0" marginwidth="0" marginheight="0" scrolling="yes"><br />
    <frame name="mainFrame" id="mainFrame" src="mainFrame.html" frameborder="0" marginwidth="0" marginheight="0"><br />
    </frameset><br />
    <noframes><br />
      <body></p>
<div>
          Das HTML-Frameset kann von Ihrem Browser leider nicht angezeigt werden.
        </div>
<p>      </body><br />
    </noframes><br />
</frameset><br />
[/code]</p>
<p>Nehmen wir also an, daß unsere JS Code gerade in leftFrame ausgeführt wird und das wir in mainFrame auf ein DOM Element zugreifen wollen. Wir müssen also von leftFrame auf parent, dann auch mainFrame, dann auf dessen DOM und dort das DOMElement suchen. Hier nun der korrekte JS Code</p>
<p>[code lang='javascript']<br />
parent.$(mainFrame).contentDocument.defaultView.$(domElement)<br />
[/code]</p>
]]></content:encoded>
			<wfw:commentRss>http://leine.info/2009/01/prototype-und-frames/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Prototype Insert, oder wie füge ich Elemente richtig ein</title>
		<link>http://leine.info/2009/01/prototype-insert-oder-wie-fuge-ich-elemente-richtig-ein/</link>
		<comments>http://leine.info/2009/01/prototype-insert-oder-wie-fuge-ich-elemente-richtig-ein/#comments</comments>
		<pubDate>Fri, 16 Jan 2009 09:32:29 +0000</pubDate>
		<dc:creator>jleine</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[Element]]></category>
		<category><![CDATA[Prototype]]></category>

		<guid isPermaLink="false">http://leine.info/?p=53</guid>
		<description><![CDATA[Neulich bin ich über ein triviales Problem gestoplert. Ich wollte eigentlich eine rechte simple DOM Manipulation mit Hilfe von Prototype realisieren. Doch leider hatte ich so meine Schwierigkeiten mit der Prototype Doku. Folgendes war meine Ausgangssituation: [code lang='xhtml'] Some navigation &#8230; <a href="http://leine.info/2009/01/prototype-insert-oder-wie-fuge-ich-elemente-richtig-ein/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Neulich bin ich über ein triviales Problem gestoplert. Ich wollte eigentlich eine rechte simple DOM Manipulation mit Hilfe von <a href="http://www.prototypejs.org">Prototype</a> realisieren. Doch leider hatte ich so meine Schwierigkeiten mit der Prototype Doku.<span id="more-53"></span></p>
<p>Folgendes war meine Ausgangssituation:<br />
[code lang='xhtml']</p>
<div id="site">
<div id="navigation">Some navigation stuff</div>
<div id="content">Lorem ipsum dolor sit amet, consetetur sadipscing elitr,<br />
  sed diam nonumy eirmod tempor invidunt ut labore et dolore magna<br />
  aliquyam erat, sed diam voluptua.</div>
</div>
<p>[/code]<br />
In dieses div Snippet wollte ich nun ein weiteres DIV Element mit der id <em><strong>contentIntroduction</strong></em> einfügen. Dabei sollte dieses div genau zwischen die zwei bestehenden divs <em><strong>navigation</strong></em> und <em><strong>content</strong></em> eingefügt werden. Ein kurzer Blick in die <a href="http://www.prototypejs.org/api/">Prototype API</a> führte dann auch gleich die<a href="http://www.prototypejs.org/api/element/insert"> Element.insert Methode</a> zu Tage. Leider ist die Dokumentation an dieser Stelle ein wenig dürftig, weshalb ich zunächst auch etwas rumprobieren musste, bis ich es wirklich verstanden habe.</p>
<p>Für mein beschriebenes Problem müsste die <a href="http://www.prototypejs.org">Prototype</a> Variante also folgendermaßen aussehen.<br />
[code lang='xhtml']<br />
var contentIntroductionElement = new Element('div', {<br />
  'id'   : 'contentIntroduction',<br />
  'class': 'intro',<br />
}).update('This is a simple and short content introduction');</p>
<p>var contentElement = $('navigation');</p>
<p>Element.insert(contentElement, {'after': contentIntroductionElement});<br />
[/code]</p>
<p>Zu lesen ist das Ganze folgendermaßen. Klasse Element, hole Dir das DOM-Element <strong><em>navigation</em></strong> und füge danach das DOM-Element <strong><em>contentIntroductionElement</em></strong> ein. Es muss natürlich nicht nur before sein. <a href="http://www.prototypejs.org">Prototype</a> lässt auch <strong><em>before</em></strong>, <strong><em>top</em></strong> und <strong><em>bottom</em></strong> zu.</p>
<p>Das Ergebnis sind dann folgendermaßen aus:<br />
[code lang='xhtml']</p>
<div id="site">
<div id="navigation">Some navigation stuff</div>
<div id="contentIntroduction" class="intro">This is a simple and short<br />
  content introduction</div>
<div id="content">Lorem ipsum dolor sit amet, consetetur sadipscing elitr,<br />
  sed diam nonumy eirmod tempor invidunt ut labore et dolore magna<br />
  aliquyam erat, sed diam voluptua.</div>
</div>
<p>[/code]</p>
]]></content:encoded>
			<wfw:commentRss>http://leine.info/2009/01/prototype-insert-oder-wie-fuge-ich-elemente-richtig-ein/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tablekit</title>
		<link>http://leine.info/2009/01/tablekit/</link>
		<comments>http://leine.info/2009/01/tablekit/#comments</comments>
		<pubDate>Thu, 15 Jan 2009 17:49:15 +0000</pubDate>
		<dc:creator>jleine</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Prototype]]></category>
		<category><![CDATA[Tablekit]]></category>

		<guid isPermaLink="false">http://leine.info/?p=43</guid>
		<description><![CDATA[Heute möchte ich euch auf eine kleine, aber feine, JavaScript Bibliothek namens Tablekit hinweisen. Jeder Programmierer kennt wahrscheinlich das Problem. Große tabellarische Daten müssen in irgendeiner Form besser aufbereitet werden. Die Anzeige auf einer Website ist meistens schnell erledigt, doch &#8230; <a href="http://leine.info/2009/01/tablekit/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Heute möchte ich euch auf eine kleine, aber feine, JavaScript Bibliothek namens <a href="http://www.millstream.com.au/view/code/tablekit">Tablekit</a> hinweisen. Jeder Programmierer kennt wahrscheinlich das Problem. Große tabellarische Daten müssen in irgendeiner Form besser aufbereitet werden. Die Anzeige auf einer Website ist meistens schnell erledigt, doch wie sieht es aus, wenn der User ein wenig mehr Anwendungskomfort haben möchte? Stichwort Sortierung? Die Tabelle, die schön vom Server aufbereitet wird, muss beim User auch umkompliziert sortierbar sein und zwar egal nach welcher Spalte.<span id="more-43"></span></p>
<p>Kein Problem denkt sich der Programmierer und erweitert die  Backendmethoden seiner DAO&#8217;s um eine Sortiermöglichkeit. Das Ganze wird dann aber etwas schwieriger oder ressourcenfressender wenn man eine Sortierung von komplexen JOIN Statements  sortierbar machen will. Im schlimmsten Falle wählt der User nämlich immer genau die Sortierung aus, die aus DB Sicht gar nicht schlau oder ideal ist. Eine Sortierung einer Spalte, wo kein Index oder Primary Key vorhanden ist kann so schnell zu Höllenqual werden und nicht selten leidet dann die Komplexität des Backendcodes darunter.</p>
<p>Wie wäre es also mit einer Lösung für den Client? Wenn der User schon mitunter komische Sorierungsmöglichkeiten haben will, warum sollte dann dies nicht der Client selbst machen? Vorteil wäre, daß der Server nicht unnötig durch andauernde Sortierrequest lahm gelegt wird und der User hat obendrein noch das Gefühl, daß die Sortierung sehr schnell geht.</p>
<p>Eben dieser Usecase lässt sich ganz leicht mit der JS Bibliothek <a href="http://www.millstream.com.au/view/code/tablekit">Tablekit</a> realisieren. Der Programmierer muss noch nicht einmal besonders begabt sein, denn alles was benötigt wird ist eine zusätzliche CSS Klassenangabe im table tag. Klingt einfach, oder?</p>
<p>Ist es auch. Um Tablekit zu verwenden benötigt man nur <a href="http://www.prototypejs.org">Prototype</a> als Basisbibliothek und eben <a href="http://www.millstream.com.au/view/code/tablekit">Tablekit</a>. Danach muss man nur noch alle table tags mit der von Tablekit vorgegebenen Klassebezeichnung <strong>sortable</strong> auszeichnen und schon erstrahlt die Tabelle in neuer Funktionsvielfalt. Über JS ermittelt Tablekit zunächst den verwendeten Datentyp, denn ein Datum wird immer noch anders sortiert als ein String. Ist der Datentyp bestimmt, sortiert <a href="http://www.millstream.com.au/view/code/tablekit">Tablekit</a> entsprechend. Programmieraufwand gleich null. Den Programmierer, den Server, die DB und den Endanwender wird es freuen.</p>
<p>Ein paar Einschränkungen gibt es dann aber doch. Tablekit sortiert immer nur die Datenmenge, die auch zum Zeitpunkt des Renderings vorhanden ist. Sollte eure Tabelle also einen Paging Mechanismus verwenden, dann wird Tablekit auch nur diese entsprechend sortieren, d.h. wenn ihr z.b. die zweite Seite einer Tabelle sortiert, dann wird auch leider nur diese Seite sortiert und nicht die gesamte Datenmenge. Wie denn auch? Trotzdem ist <a href="http://www.millstream.com.au/view/code/tablekit">Tablekit</a> hier eine schnelle und hervorangende Wahl, um mit möglichst geringen Aufwand schnelle Ergebnise zu erzielen.</p>
]]></content:encoded>
			<wfw:commentRss>http://leine.info/2009/01/tablekit/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

