more

Kleiner historischer Exkurs

Letztens bin ich nach “Full Metal Jacket” auf den Wikipedia-Seiten zum Vietnamkrieg hängen geblieben. Zwei Dinge sind mir aufgefallen:

  1. Die blutigsten Kriege können diejenigen sein, die eigentlich keiner wollte.
  2. Aus Frust und Hochmut entsteht sehr leicht Barbarei (und zwar flächendeckend und systematisch, nicht nur in My Lai).
  3. Und wer genau hielt das brennende Streichholz an die Lunte mit dem Pulverfass?

Am 4. August [1964] meldete die USS Turner Joy (DD-951) während eines Gewitters irrtümlich weitere Torpedoangriffe, zog die Meldung aber zurück. Die NSA legte Johnson nur jene 10 % des für den Zwischenfall relevanten Funkverkehrs vor, die einen Angriff nahelegten. Johnson ordnete am selben Abend erste Luftschläge auf Hanoi an und begründete diese im US-Fernsehen als Vergeltung für „wiederholte unprovozierte Gewaltakte“. (Wikipedia)

Die NSA hat also ihren eigenen Präsidenten belogen und dadurch einen Konflikt mit schätzungsweise 4 Millionen Toten ausgelöst. Kein Wunder, dass die nicht verstehen, warum wir uns wegen des bisschen Bespitzelns so aufregen.

Ingress-Regress

Wie ich höre, hat Google nun allen den Zugang zu ihrem Augmented-Reality-Spiel Ingress ermöglicht. Einige meiner befreundeten c’t-Kollegen sind begeistert von Ingress und spielen es auf Level 7 oder 8.

Mich hat Ingress auch mal interessiert, aber nicht sehr lange. Vor etwa zwei Monaten habe ich die App zum letzten Mal geöffnet. Falls seitdem irgendwelche coolen Features dazugekommen sind: Sorry, habe ich nicht mitgekriegt.

Ingress hat für mich das Niveau einer grafisch toll umgesetzten Schnitzeljagd. Strategie? Möglichst viele Hot Spots abfahren. Taktik? Mit anderen unterwegs sein.

Die Einen sagen, man geht dank Ingress mit offeneren Augen durch die Stadt, aber in meiner Ingress-Zeit habe ich dabei vor allem aufs Handy geschaut. Andere nutzten den Anreiz, sich mit anderen Leuten zusammenzutun, aber das ist nicht so mein Ding. Als Level-1-Spieler in der Vorstadt irgendwelchen Kram von Portalen einsammeln, mit dem man eh fast nichts anfangen kann, ist jedenfalls nichts, was mich länger als vielleicht einen Monat bei der Stange gehalten hat.

Dabei ist doch offensichtlich, dass Augmented-Reality-Spiele der Knaller sein könnten. Wieso macht das sonst keiner?

Zum Beispiel eines dieser klassischen Aufbauspiele: Beim Nachbarn drüben Holz sammeln, damit man das eigene Haus besser befestigen kann. Gebäude errichten, zu Territorien zusammenschließen … das ist doch naheliegend. Gegen einen niedrigen sechsstelligen Betrag werde ich gerne ein größeres Unternehmen aus der Spielebranche beraten (offenbar kommt die ja nicht von selbst darauf).

Thoughts and Observations about HTML Custom Elements

I just finished a story about HTML Custom Elements, templates and Shadow DOM which is due to appear in one of the coming issues of c’t magazin.

If you never heard about HTML Custom Elements and all the other stuff defined in the Web Components Spec read about it here or here. In a nutshell you can:

  • define HTML elements of your own in JavaScript;
  • use HTML templates;
  • hide parts of a DOM and encapsulate stylesheets in a Shadow DOM;
  • combine HTML templates and Shadow DOM for the definition of your HTML Custom Elements.

Without giving away too many details of my article I’d like to share a few of my conclusions and findings:

  1. When I started experimenting with Custom Elements I thought I had missed something. I chose a prototype like HTMLButtonElement – but my new element wasn’t looking like a button at all.
    Turns out you have to define everything yourself. The browser doesn’t care what element prototype you decided for. There isn’t even a difference to HTMLUnknownElement whose prototye is used when you insert an undefined element into the document.
    This is unsatisfactory and should be changed. Picking a prototype must have a meaning. There should be a way to copy <button> into <my-button> and supercharge it with extra features. Well, there is one: I’ll have to add the extends property to the prototype. But then I can only call my element as <button is="my-button"> which feels considerably less sexy.
  2. While HTML Custom Elements are sweet I’d expect templates and Shadow DOM to have an even greater impact. Templates are already in use with JavaScript frameworks like Backbone or AngularJS but the syntax is a hack (the template dwells inside a script element with a custom type attribute value).
    Shadow DOM adds something to web development that you couldn’t have done before. Encapsulation feels good in a hardly controllable environment. Coincidentally we are getting encapsulation features in JavaScript, too.
  3. By playing around with Polymer I soon got accustomed to its style of custom element definition: a <polymer-element> element with a template and a simple binding mechanism. That is how it should be. <polymer-element> is a variation of <element> which was part of the original Web Components drafts. But they put them on hold because of technical problems.
    That’s not good – and I have trouble understanding it. They can’t solve the problems in the native browser code but they can in a JavaScript library?
  4. Is there a problem with complex CSS selectors like p:first-of-type in templates or in the Shadow DOM? I didn’t get them to work and don’t quite understand why.

Anyway: I’m looking forward to the time when we can use the goodies from Web Components. Maybe next year?

Unerwartete Browser-Probleme: HTTP-Weiterleitungen

Eben habe ich ein ziemlich kniffliges Problem gelöst, das beim Relaunch unserer Feigenblatt-Website aufgetreten ist. Das Fiese daran war eine Browser-Inkompatibilität an einer Stelle, an der ich nie damit gerechnet hätte.

Die Website basiert auf WordPress und sollte statt meiner selbstgebastelten Skripte ein ordentliches Shop-System kriegen — wpShopGermany. Doch auch daran habe ich kräftig rumgedoktert, um zum Beispiel direkt auf die Produktübersicht einen “In den Warenkorb”-Button zu platzieren statt nur auf den einzelnen Produktseiten.

Weil Anja auch auf dem Sofa an der Seite feilen wollte und kein anderer Laptop frei war, nahm sie als Entwicklungsmaschine ein … Netbook. Ja, nicht gerade ideal. Aufwendige Tests auf verschiedenen Browsern waren jedenfalls nicht drin, denn das Teil war mit Server-Umgebung, Editor und Firefox mehr als ausgelastet.

Dieses Wochenende haben wir gelauncht. Eher zufällig bemerke ich: Wenn man mit Chrome den Warenkorb-Button anklickt, kommt eine weiße Seite. Mit Firefox klappt es dagegen. Weitere Tests ergeben, dass alle WebKit/Chromium-Browser so reagieren wie Chrome, während sich der IE wie Firefox verhält.

Was war passiert? Nach dem Klick auf den Button schickt der Browser einen POST-Request los:

POST /bestellen/ HTTP/1.1
Host: www.feigenblatt-magazin.de
Content-Length: 74
Origin: http://www.feigenblatt-magazin.de
Content-Type: application/x-www-form-urlencoded

Der Server antwortet darauf:

HTTP/1.1 302 Moved Temporarily
Server: Apache
Location: 
Content-Length: 0
Content-Type: text/html

Schaut man sich das an, scheint die Reaktion von Chrome, Safari etc. recht logisch zu sein: Es gibt eine Weiterleitung, aber keine URL — zeigen wir eine leere Seite. Firefox und Internet Explorer machen dagegen etwas Seltsames: Sie interpretieren diese Antwort als Hinweis, die gleiche Adresse mit einem GET-Request zu befragen. Die Server-Skripte sind so konfiguriert, dass sie darauf eine gültige Seite zurückgeben, während POST-Anfragen den 302 serviert kriegen.

Dieses Verhalten hat offenbar mit einer umstrittenen Interpretation von HTTP 302 zu tun:

Many web browsers implemented this code in a manner that violated this standard, changing the request type of the new request to GET, regardless of the type employed in the original request (e.g. POST). (Wikipedia)

Tatsächlich scheinen alle gängigen Browser als Antwort auf einen 302 einen GET-Request abzusetzen. Für Firefox und Internet Explorer hat das aber sogar Priorität über der Zieladresse. Wer hätte gedacht, dass es da so große Unterschiede zwischen den Browsern gibt.

Gelöst habe ich das Problem übrigens durch ein zusätzliches Feld in den übertragenen Formulardaten (“myReferer” mit der Zieladresse), welches den Serverskripten von wpShopGermany das korrekte Weiterleitungsziel mitteilt.

Fever-Zäpfchen

Mein Artikel über Nachfolger für den Google Reader war auch eine Recherche in eigener Sache, weil ich Newsfeeds intensiv nutze. Obwohl mir unter den selbstgehosteten Diensten auch selfoss gut gefallen hat, nutze ich seit ein paar Wochen Fever.

Auf dem Pre funktionierte die Mobil-Ansicht gut, auf dem neu gekauften Nexus 4 nicht. Die raumgreifend breite Desktop-Darstellung taugt überhaupt nicht für eine drei Finger breiten Bildschirm. Mit Meltdown gibt es eine Android-App für Fever, aber die ist ziemlich primitiv und macht keine Spaß. Also habe ich mal geschaut, ob ich das Problem bei Fever lösen kann. War nicht besonders schwer:

Fever entscheidet im PHP-Code anhand der Browser-Kennung, welchen View es wählt. In der Datei firewall/app/libs/fever.php lauten die Zeilen 340ff:

$this->is_mobile =
(
  isset($_SERVER['HTTP_USER_AGENT']) &&
  strpos($_SERVER['HTTP_USER_AGENT'], 'AppleWebKit') &&
  m('#(iPhone|iPod|Pre|Pixi|Android|webOS)#', $_SERVER['HTTP_USER_AGENT'], $m)
);

“AppleWebKit” ist nicht in der Nexus-Browserkennung enthalten — daher kommentiert man diese Zeile am besten aus. Das hat allerdings zur Folge, dass plötzlich auch der Desktop-Opera die Mobil-Ansicht kriegt: Der reguläre Ausdruck in der Zeile darunter erwischt nämlich auch das “Presto” in der Opera-Browserkennung. Das lässt sich zum Beispiel so reparieren:

m('#(\b(iPhone|iPod|Pre|Pixi|Android|webOS)\b)#', _etc._)

Lädt man die geänderte Datei hoch, zeigt das Nexus mit Chrome, Opera Mobile und Firefox Fever brav in der Mobilansicht dar. Die Zoomstufe passt aber nicht — was mit voreingestellter Vergrößerung in hochauflösenden Displays zu tun hat — und, schlimmer noch: Sie lässt sich nicht verstellen.

Schön, dass man in HTML eine Default-Zoomstufe einstellen kann, aber ich weiß nicht, warum man Zoomen verbieten sollte. Also legen wir Hand an Zeile 7 von firewall/app/views/mobile/page/header.php:

<meta name="viewport" id="viewport" content="initial-scale=1.0,user-scalable=no,minimum-scale=1.0,maximum-scale=1.0" />

Ich schlage vor:

<meta name="viewport" id="viewport" content="initial-scale=0.8,user-scalable=yes" />

Und wo wir gerade dabei sind: In der Mobilvariante benutze ich die Einzelansicht, bei der man mit “Next”- und “Previous”-Buttons von Nachricht zu Nachricht navigiert. Diese Buttons sind unterhalb der Nachricht, was mich aus zwei Gründen stört: Erstens muss ich scrollen, auch wenn mich die Nachricht nicht interessiert, zweitens kann sich das Laden der Buttons bei schlechter Verbindung oder lahmem Gerät (Palm Pre!) einige Sekunden hinziehen.

Ändern kann man das in firewall/app/views/mobile/reader/item.php, wo Zeile 94 bis 102 ein <div class="footer"> definieren. Es mag ein bisschen sonderbar sein, den Footer über dem Header zu platzieren, und vielleicht sieht es auch nicht schön aus, aber Usability schlägt Ästhetik — also hoch mit dem Block in Zeile 65 unterhalb von <div id="item">.