flkzrrrnr0
Category Archives: Web
AddToHomescreen: pin web apps to the homescreen
Apples iOS supports since ages a meta tag called “apple-mobile-web-app-capable”, with which a developer can tell iOS that web site doesn’t need navigation and url bars and is handling that itself. So, if this meta tag is set and a web site is called from the iOS homescreen it looks like a normal app for the normal visitor.
The problem is to tell its visitors that this behaviour is supported as most users don’t know that there is even the possibility to add websites to their homescreens.
But like they say – there is an app for that – there is a library for that: Matteo Spinelli has developed the wonderful tool AddToHomescreen. If you embed the code inside your web app, a small tooltip will be visible after page load which asks the user to add the site to their homescreen. The library checks itself that its only visible on compatible iOS devices and changes the little icon what the user should tap on automatically (its different on iPads and iPhones). Additionally you can configure some options like if and how long the tooltip stays or how long the tooltip remembers that the user has closed the tooltip and will not see it again.
After optimizing and deleting not-needed languages its payload is only 6 kB.
Attention if you are using requireJS
AddToHomeScreen uses the onload event to init itself by default, but that event is already gone when loading it via requireJS … at least when using it together with r.js optimizer (which you should!). But there is a (advanced) config option for this:
If this option is set, the library inits itself as soon as its loaded and doesn’t wait for the (already gone) load event.
jQuery Mobile: display listviews in a grid
Recently we had the requirement in our mobile web app which is using jQuery mobile to use a two-column grid view. Inside the columns a listview should display some data (data-role=listview). Out of the box that doesn’t look good with jQuery Mobile 1.2 as margins and paddings of the containers outside the listviews are messed up.
But its surpringly easy to alter the paddings and margins so that it looks as expcted when displaying two listviews next to each other:
<div data-role="content" style="padding: 0;"> <div class="ui-grid-a" style="padding: 15px;" > <div class="ui-block-a"> <ul data-role="listview" data-theme="e"> <li data-role="fieldcontain"><a>Eins</a></li> <li data-role="fieldcontain"><a>Zwei</a></li> <li data-role="fieldcontain"><a>Drei</a></li> </ul> </div> <div class="ui-block-b"> <ul data-role="listview" data-filter="true"> <li data-role="fieldcontain"><a>Eins</a></li> <li data-role="fieldcontain"><a>Zwei</a></li> <li data-role="fieldcontain"><a>Drei</a></li> </ul> </div> </div> </div>
All you need to do is to set the padding of the content div to 0 and add the now missing padding to the first grid container (“ui-block-a”.
And done.

Appcache Manifest erstellen und in einer angularJS App integrieren
Wer eine ausgewachsene App entwickelt, die aus rein statischen Dateien (*js, *.css, *.html) besteht und die dynamischen Daten ausschließlich über einen REST-Server nachlädt, sollte sich in jedem Fall mal mit dem HTML5 Appcache beschäftigen. In so einem Fall kann man die (z.B. bei alistapart etwas übertriebenen beschriebenen) Nachteile nämlich ruhig ignorieren.
Der Vorteil für den Nutzer die kompletten statischen Daten immer sofort auf dem Gerät parat zu haben und außer dem REST-Request überhaupt keine HTTP-Requests zum Laden der App zu benötigen, ist speziell für mobile Anwendungen ein ungeheurer Performancegewinn.
Wie ein Appcache-Manifest aufgebaut ist, wird z.B. auf HTML5 Rocks beschrieben.
Nun will man die Datei aber natürlich möglichst automatisch erstellen. Wir haben uns – da wir grunt als Buildtool verwenden – für grunt-contrib-manifest entschieden. Für mich ein weiterer Grund sehr zufrieden mit unserer Entscheidung zu sein, grunt zu verwenden. Es gibt für praktisch alle Anforderungen im Bereich Webentwicklung bzw. Frontend-Entwicklung bereits ein Plugin. [highlight1]”Da gibts ein Plugin für”[/highlight1] statt “Da gibt’s eine App für” sozusagen 🙂
Die Konfiguration ist simpel und selbsterklärend, da muss ich nicht weiter drauf eingehen. Und funktioniert bisher problemlos.
Was etwas mehr nachdenken erfordert hat, war, wie man auf das Event “updateready” reagieren soll, das der Browser erzeugt, wenn er die Dateien im Appcache vollständig aktualisiert hat und die neue Version der App geladen werden muss. Dass eine nicht wegklickbare Info-Box erscheinen sollte, die der Nutzer nur mit einem Klick auf “Neu laden” schließen können sollte, war recht schnell klar. Das eigentliche “Problem” war, das solche DOM-Manipulationen nicht in einen angularJS Controller gehören. Schließlich sollen die auf jeden Fall auch ohne DOM unittest-bar bleiben.
Also war eine Direktive notwendig.
Wir haben es momentan mit dieser Direktive gelöst. Das Popup benutzt jQuery Mobile.
function AppcacheUpdated() { var elementScope; window.applicationCache.addEventListener('updateready', function() { if (window.applicationCache.status === window.applicationCache.UPDATEREADY) { window.applicationCache.swapCache(); elementScope.show = true; if (!elementScope.$$phase) { elementScope.apply(elementScope.show); } } }); return { restrict:'E', template:" <div data-role='popup' class='appcachePopup ui-content' data-theme='e'>" + " <p><translate>Neue Version</translate></p><br />" + "<a ng-click='reload()' data-role='button'>Neu laden</a> </div>", scope:{ }, controller: function ($scope){ $scope.$watch("show", function(value) { if (value) { $(".appcachePopup").popup("open", {dismissible:false}); } }); $scope.reload = function() { window.location.reload(); }; $scope.show = false; }, link: function (scope) { elementScope = scope; } }; } angularModule.directive("appcacheUpdated", AppcacheUpdated);
Die Direktive zu verwenden ist simpel, einfach in jede HTML-Seite, auf der sie verwendet werden soll, irgendwo einbauen:
<appcache-updated></appcache-updated>
Das ist so ziemlich meine erste Direktive. Mal schauen ob sie auch weiterhin so funktionieren wird, wie sie es momentan tut. Oder ob es dort noch Fallen gibt, über die ich bisher nicht gestolpert bin. Vor allem bin ich mir momentan noch etwas unsicher, ob es günstig ist, sich den “element.$scope” in einer Closure zu merken.
Die Komplexität um angularJS-Direktiven zu schreiben, ist aber in jedem Fall deutlich geringer als JSF-Komponenten zu schreiben. Ich bin immer mehr der Überzeugung, dass JSF für mich keine Zukunft mehr hat, wenn es um Frontend-Entwicklung geht. Der Ansatz auf dem Server das HTML zu rendern und den Client darstellen zu lassen, hat sich in den letzten Jahren einfach überlebt.
Die Entwicklung mit angularJS ist erstens deutlich einfacher und zweitens … macht es einfach Spass. 🙂
Javascript in der IDE debuggen mit Webstorm
Gleich vorweg, das Video ist nicht von mir und hat auch keinen Ton.
Nichtsdestotrotz sieht man dort sehr schön wie man mit der aktuellen Testacular Version in der aktuellen Webstorm Version Javacscript direkt in der besten Javascript IDE debuggen kann, die es momentan gibt: Webstorm.
Das ist nicht übertrieben. Die Jungs von Jetbrains sind momentan absolut führend in der Integration von Javascript in einer IDE. Wer keinen reinen Editor wie Sublime verwenden möchte sondern eine ausgewachsene sinnvoll vorkonfigurierte IDE, dem bleibt nur Webstorm.
Trotz des Videos hier nochmal die wichtigsten Konfigurationsfenster zusammengefasst. Es wird eine laufende Testacular Installation vorausgesetzt, wie das z.B. geht habe ich z.B. in meinem Artikel erklärt.
Die gesamte Konfiguration ist in 2-3 Schritten erledigt und baut auf die “Run/Debug Configurations” auf. Die sind über die Icon-Leiste erreichbar (siehe Bild).
Dort kann man zwei oder drei Konfigurationen anlegen. Drei benötigt man, wenn die Tests nicht automatisch nach jedem Speichern laufen sollen, sondern auf Knopfdruck.
Die erste Konfiguration ist der Server (siehe Bild). In dem Menü muss man über das + eine neue node.js Konfiguration anlegen. Die dort einzutragenden Werte seht ihr auf dem Bild. Die Pfade sind entsprechend anzupassen, auf dem Bild sind die Pfade für einen Mac zu sehen.
Die zweite (optional) anzulegende Konfiguration, ist die manuelle Ausführung der Tests, wenn der Server nicht automatisch loslegen soll (abhängig von der Konfiguration in der testacular.conf.js). Auch hier muss wieder eine node.js Konfiguration angelegt werden und als Startparameter für Testacular gibt man diesmal nur “run” an. Das wars schon.
Jetzt kann man bereits die Tests ausführen und man sieht die Ergebnisse in der Konsole. Wenn Fehler aufgetreten sind, sieht man dort die Dateien, die alle anklickbar sind sodass man direkt an der betreffenden Codestelle landet.
Wenn man nun noch debuggen möchte, fügt man wieder über das + und “Javascript Debug” eine “Remote” Konfiguration hinzu. Die genaue Konfiguration ist wieder auf dem Bild sichtbar. Spannend ist hier nur die Wahl des Browsers (aktuell Chrome oder Firefox) und die Remote URL. Im Fall von Testacular und dem Standardport ist das [highlight1]http://localhost:9876/base[/highlight1]
Das wars. Man kann den vorher angelegten Server nun nicht mehr nur starten, sondern über das Debug-Icon auch debuggen. Das startet den gewählten Browser und stellt eine Verbindung her. Das debugging sollte direkt funktionieren, das genaue Vorgehen sieht man in obigem Video.
[fancy_images]
[image title=”Run/Debug Configurations” caption=”Run/Debug Configurations”]http://entwicklertagebuch.com/blog/wp-content/uploads/2013/01/editconfigurations.png[/image]
[image title=”Testacular Server starten” caption=”Testacular Server starten”]http://entwicklertagebuch.com/blog/wp-content/uploads/2013/01/server.png[/image]
[image title=”Testacular Tests starten” caption=”Testacular Tests starten”]http://entwicklertagebuch.com/blog/wp-content/uploads/2013/01/run.png[/image]
[image title=”Testacular Debug Konfiguration” caption=”Testacular Debug Konfiguration”]http://entwicklertagebuch.com/blog/wp-content/uploads/2013/01/debug.png[/image]
[image title=”Testacular Server gestartet” caption=”Testacular Server gestartet”]http://entwicklertagebuch.com/blog/wp-content/uploads/2013/01/serverstarted.png[/image]
[/fancy_images]

angularJS App mit requireJS und Testacular testen
Wie schon ein paar mal geschrieben, bin ich schwer begeistert wie einfach es mit angularJS ist, Web Apps mit Javascript zu entwickeln. Vielleicht merkt man das auch an der ein oder anderen Stelle 🙂
Aber egal, wie einfach das Entwickeln ist, wir machen alle Fehler. Deshalb muss auch angularJS-Code getestet werden, mindestens Unit-Tests besser noch mit End-2-End-Tests.
[highlight1]Aber moment mal, Javascript-Code und Unit-Tests? Geht das überhaupt? [/highlight1]
Aber klar! Schon lang gibt es diverse Test-Frameworks für Javascript. jQuery benutzt z.B. qunit, die AngularJS-Entwickler bevorzugen Jasmine.
Als Skriptsprache, die beim Kunden im Browser ausgeführt wird, ist es bei Javascript-Tests natürlich wichtig, sie dort auszuführen wo sie laufen: im Browser. Und das ist ohne spezialisierte Tools äußerst aufwändig.
Als sogenannter Test Runner, gibt es seit einigen Jahren jsTestDriver (von Google), das Unit-Tests entgegennimmt und dafür sorgt, sie auf angeschlossenen Browsern auszuführen. Leider habe ich keine gute Erfahrung damit gemacht, da es allgemein recht instabil läuft, mehrfach täglich neugestartet werden muss und nach Neustart das automatische Wiederverbinden mit den Browsern eher hakelig ist. Außerdem scheint die Weiterentwicklung auch eher eingeschlafen zu sein.
Die AngularJS-Entwickler haben sich deshalb entschlossen, einen eigenen Test Runner zu entwickeln. [highlight1]Testacular[/highlight1].
Testacular ist kein Testframework, sondern wirklich nur der Test Runner. Man schreibt die Unit-Tests also z.B. als Jasmine-Tests und führt sie mit Testacular in Chrome oder Firefox oder Safari oder auch in PhantomJS (Headless Browser) aus.
Da wir AngularJS u.a. auch mit requireJS benutzen, ist es allerdings nicht ganz einfach, als Anfänger zu verstehen, wie man Testacular konfigurieren muss, damit requireJS den Produktions- und Testcode asynchron nachladen kann und erst danach Testacular loslegt um die Tests auszuführen.
Standardmässig liefert Testacular nämlich eine Webseite an den Browser aus, in der alle referenzierten *.js-Dateien automatisch als <script>-Tag referenziert werden, damit der Browser sie lädt. Nach Laden der Seite fängt dann Testacular an, die Tests auszuführen. Mit requireJS darf Testacular allerdings die Skripte eben gerade nicht mittels <script>-Tag laden, sondern dies übernimmt require.js. Nur die main.js um requireJS zu laden und zu konfigurieren, darf so eingebunden werden.
Als Startpunkt für meine Konfiguration mit requireJS habe ich einen Artikel bei Jake Trent gefunden, der sich genau diesem Problem widmet. Im Gegensatz zu diesem Artikel kann ich aber sagen, dass die komplette requireJS-Konfiguration wie man sie im Produktionsbetrieb gewohnt ist, auch für Testacular funktioniert. Testacular bindet mit meiner Konfiguration nur noch Jasmine, requireJS und die main-test.js ein. Alles andere lädt requireJS nach.
Dies erreicht man mit folgender Konfiguration der Dateien:
files = [ JASMINE, JASMINE_ADAPTER, REQUIRE, REQUIRE_ADAPTER, {pattern:'src/main/external-libs/angular-1.0.3.js', included:false}, {pattern:'src/test/external-libs/angular-mocks-1.0.3.js', included:false}, {pattern:'src/main/js/**/*', included:false}, //Produktionscode {pattern:'src/test/unit/**/*.js', included:false}, //Testcode 'src/test/main-test.js' //requireJS-Konfiguration ];
Entscheidend ist hier das [hightlight1]included:false[/highlight], was dafür sorgt, dass die Dateien zwar verfügbar sind, aber nicht per <script> automatisch ausgeliefert werden. Der Rest der Konfiguration kann so aus dem verlinkten Artikel übernommen werden.
In der main-test.js Datei muss man nun dafür sorgen, dass die eigene Anwendung geladen wird (die ja sowieso schon aus require-Module bestehen sollte), die Testklassen geladen werden (das müssen nun auch alles require-Module sein, siehe Artikel) und wenn das alles geladen ist, muss Testacular mitgeteilt werden, dass es nun loslegen kann. Meine main-test.js sieht wie folgt aus:
(function (window, require) { "use strict"; var file, requireModules; requireModules = []; //aus den von Testaular bereitgestellten Dateien alle *Test-Dateien raussuchen und Pfad anpassen, damit requireJS //was damit anfangen kann for (file in window.__testacular__.files) { if (window.__testacular__.files.hasOwnProperty(file)) { if (file.substring(file.length - 7, file.length) === 'Test.js') { requireModules.push("../.." + file.substring(9, file.length - 3)); } } } // unsere eigene Anwendung inkl. Abhängigkeiten laden requireModules.push("app"); //angular Mocks laden requireModules.push("mocks"); require({ // "/base" ist die URL von der Testacular alle Dateien ausliefert, // "src/main/js" ist due Base-URL aller Module die nicht Test sind baseUrl:'/base/src/main/js', paths:{ 'angular':'../external-libs/angular-1.0.3', 'mocks':'../../test/external-libs/angular-mocks-1.0.3' }, shim:{ 'angular':{ exports:'angular' }, 'mocks':{ deps:['angular'], exports:'mocks' } } }, requireModules, function () { //erst hier wird Testacular tatsächlich (manuell) gestartet window.__testacular__.start(); }, function (err) { //hier kommt die Fehlerbehandlung hin }); }(window, require));
Über den Zugriff auf [highlight1]window.__testacular__.files[/highlight1] hole ich mir alle Testdateien und bastele daraus die korrekt benamten require-Module. Dann wird noch die eigentliche Anwendung und Angular hinzugefügt. Wenn requireJS alles geladen hat, wird dann über [highlight1]window.__testacular__.start();[/highlight1] Testacular gestartet.
Wenn man das einmal begriffen hat, ist es eigentlich recht einfach. Aber das ist ja häufig so 🙂 Testacular ohne requireJS zu konfigurieren, ist auch deutlich einfacher.
Wenn es dann einmal läuft, hat man aber einen hervorragenden Testrunner, den man dann auch in Webstorm (Javascript IDE) integrieren kann, um direkt in der IDE, die Unit Tests starten zu können und – besonders beeindruckend – auch direkt in der IDE debuggen kann.
Aber dazu ein anderes mal mehr Details.

Kleine Vorstellung von AngularJS
Momentan bin ich recht begeistert von AngularJS, THE next best thing in der Javascript-Entwicklung. Meine nächsten Artikel werden sich wohl hauptsächlich um die Entwicklung mit diesem MVC-Framework von Google drehen.
Pascal Precht hat eine hervorragende Slideshow über AngularJS erstellt. Mit und in AngularJS. Aber seht selbst:
iOS 6 cached POST-Requests … und wie man das verhindert
Letzte Woche haben wir uns ziemlich gewundert als uns aufgefallen ist, dass unsere iPhones mit iOS 6 nicht mehr mit unserer Web App funktioniert haben. Da sind wir wohl über ein “Feature” von iOS 6 gestolpert, das ziemlich viel Aufsehen in der Entwicklergemeinde verursacht hat, als es veröffentlicht wurde.
Um dem Benutzer noch das letzte bisschen Performance vorzugaukeln, hat sich Apple nämlich entschieden, POST-Requests (z.B. per Ajax) im Browser zu cachen, wenn dies nicht explizit vom Server deaktiviert wird.
Apple steht damit ziemlich alleine … alle HTTP-Clients machen das aus gutem Grund nicht. In der “Restful HTTP”-Philosophie sind POST-Requests per Definition nicht idempotent, d.h. das Ergebnis mehrerer identischer POST-Requests an dieselbe URL selbst mit derselben Payload haben NICHT immer dasselbe Ergebnis. In SQL entspricht ein POST-Requests einem INSERT. Es werden also im Regelfall für jeden Request neue Datensätze angelegt.
POST-Requests zu cachen verbietet sich also, ausser der Serverbetreiber aktiviert es explizit mittels der üblichen HTTP-Header zum Caching.
Zwar kann ich verstehen, wenn Apple so viele HTTP-Requests sparen möchte wie es geht, damit der Benutzer möglichst performante Webseiten präsentiert bekommt, aber hier übertreiben sie ganz eindeutig.
Wenn man das Problem einmal gefunden und identifiziert hat, lässt es sich zum Glück sehr schnell deaktivieren. Wir haben im Server nun einen ServletFilter (Java) implementiert, der in alle Responses von POST-Requests zur REST-Schnittstelle den HTTP-Header [highlight1]Cache-Control: no-cache[/highlight1] einbaut.
Wenn man über den Server keine Kontrolle hat und das nicht einbauen kann, kann man als Client-Entwickler auch eine zufällige Komponente in die URL einbauen, sodass die URL immer unterschiedlich ist und iOS6 die Requests zwar cached, aber durch die wechselnde URL der Cache ins Leere läuft. Am besten geht das mit einem Timestamp:
url = url + "?" + (new Date()).getTime();
Der URL wird dann die Anzahl der Millisekunden seit 1970 angehangen.

Zentrale Lokalisierung in einer angularJS App
angularJS ist großartig und macht Spaß. Je mehr Code ich damit entwickle, umso begeisterter bin ich.
Um auch in unserer Web App einen zentralen Platz für unsere Lokalisierungen zu haben, habe ich einen Service geschrieben, der sich zentral um die Lokalisierung von allen Texten kümmern soll. Als Java-Entwickler wollte ich etwas ähnliches entwickeln, wie ResourceBundles und Properties-Dateien.
Meine Lösung ist als Angular-Service implementiert und die Lokalisierungstexte sind in JSON-Dateien ausgelagert. Der Service lädt die passende JSON-Datei asynchron per [highlight1]$http-Service[/highlight1] nach und stellt die Texte systemweit über eine [highlight1]localizationService.translate()[/highlight1]-Methode zur Verfügung. Die Lokalisierungsstrings lassen sich den Java-Properties parametrisieren, wobei die aktuelle Implementierung nur einen Parameter auswertet, weil wir aktuell nur einen benötigen. Die Formatierung greift dabei auf eine format-Methode am String-Prototyp zurück.
Hinweis: der Code um die Browsersprache zu erkennen fehlt, damit der Code einfacher zu verstehen ist.
function localizationServiceFactory($http, $q) { var translationsDE, errorMessage; function loadTranslations() { var deferred = $q.defer(); if (!translationsDE) { $http.get("/json/translations/translationsDE.json").then( function(data) { translationsDE = data; errorMessage = ''; deferred.resolve(); }, function(error) { translationsDE = {}; errorMessage = error; } ); } else { deferred.resolve(); } return deferred.promise; } function translate(key, param) { var translation = ""; return loadTranslations().then(function() { if (key) { translation = translationsDE[key]; //unbekannter Key = gib Key zurück if(!translation) { translation = key; } if (param) { translation = translation.format(param); } } return translation; }); } return { translate:translate }; } localizationServiceFactory.$inject = ['backendService', '$q']; angularModule.factory("localizationService", localizationServiceFactory);
{ "MEIN_STRING": "Das ist die Lokalisierung", "NOCH_EIN_STRING": "Und noch eine", "FALSCHER_BENUTZER": "Benutzername {0} wurde nicht gefunden." }
//format Methode, {0} {1} usw. if (!String.prototype.hasOwnProperty("format")) { String.prototype.format = function() { var formatted, i, regexp; formatted = this; for (i = 0; i < arguments.length; i++) { regexp = new RegExp('\\{'+i+'\\}', 'gi'); formatted = formatted.replace(regexp, arguments[i]); } return formatted; }; }
Das wirklich schöne an dem Service ist, dass er die JSON-Datei asynchron nachlädt, wenn sie gebraucht wird. Wenn man den Code zur Spracherkennung entsprechend baut, lädt er auch nur die tatsächlich benötigte Lokalisierung. Nicht benötigte Lokalisierungen landen erst gar nicht im Browser.
Was mich am meisten beeindruckt hat, ist der Umgang von AngularJS mit dem [highlight1]Promise-Objekt[/highlight1] das die translate-Methode in jedem Fall zurückgibt. In diesem Fall sorgt angularJS nämlich automatisch dafür, dass die Aufrufe von translate aus einem Controller heraus synchron aufgelöst werden, sodass man im Controller ohne besonderes Zutun auf jeden Fall einen lokalisierten String bekommt, obwohl der $http-Request asynchron abläuft und zum Zeitpunkt des Aufrufes eventuell noch gar nicht abgeschlossen ist.
Man könnte es fast als Magie bezeichnen 🙂

grunt – Ein Javascript Build Tool
Momentan beschäftige ich mich erstmals mit einer reinen Javascript Web App, die komplett aus statischen HTML- und JS-Dateien besteht und über eine REST-Schnittstelle mit (dynamischen) Daten versorgt wird. Als Technologien verwende ich dabei so interessante Sachen, wie [highlight1]angularJS[/highlight1], [highlight1]jQuery Mobile[/highlight1] und [highlight1]Jasmine[/highlight1]. Alles super spannend.
Aber wie verwaltet man so eine App im professionellen Einsatz, wenn man an Maven als Build-, Dependency Management- und Deployment-Tool gewohnt ist? Und im Jenkins (Continous Integration) soll es natürlich ebenfalls integrierbar sein. Und regelmässige Unit-Tests sollen auch ausgeführt werden. Und automatisch verteilte Builds, die ins automatische Deployment einlaufen.
Einfach mal die HTML- und JS-Dateien manuell ins Apache-Verzeichnis zu kopieren, kommt jedenfalls nicht in Frage.