Yoan Blanc’s weblog

Another lost swiss guy

September 2008

Playing with ARIA

Yoan BlancTue 30 September 2008, , , , , ,

I’m working with web pages for more than 6 years now, and saw things evolving a lot, the so-called web 2.0, the shift from pages to applications, from static to dynamic, from centralized publication to global publication. If the way we are using this tool to not only gather information but really interact with our peers changed, the problem of being accessible to everyone remains. And will always be there.

And the situation is maybe worse than before since we are now relying on that f-word system. The accessibility has been an important point is remains as is. A web 2.0 (or call it like you want) service can use advanced accessibility tools. It can inject extra information to his markup in order to help assisting technologies (like screen readers). To the WCAG guidelines (and its errata depending of your opinion on that case), ARIA aims to target what has been left behind by HTML, the desktop widget that has be adapted to the web like tabs, drop down menu and many more.

ARIA implementation is still a work in progress but it’s already present in Firefox 2 (and especially 3), Opera and the upcoming MSIE 8. My previous tries of building a web chat, are the kind of rich Internet application that requires these new tools to offer a similar experience like Pidgin (formerly Gaim) from a screen-reader user point of view.

Using Pidgin with Orca (the GNOME screen reader), you’ll hear every new messages coming while your cursor is in the edit field and even while you’re typing. You can achieve the same behaviour using Firefox 3 and Orca by enriching the HTML with some ARIA attributes.

Basically, it could look like that:

<h1 id="chat-title">Chat room:</h1>

<ol id="chat" aria-describedby="chat-title">
</ol>

<form onsubmit="return chat(this);" method="post" action="">
  <label for="m">
   Your message:
   <input type="text" id="m" name="m">
  </label>
  <input type="submit" value="send">
</form>

<!-- not sure about combining log and polite -->
<p id="log" role="log" aria-live="polite" aria-atomic="true">
</p<

#chat is the content of the chat room. The form to send the message, as it’s a rich application with no reloading of the page, the submit event must be caught and stopped. The chat function, will send the message over the network and maybe give the focus back to the input field. #log will be observed by the screen-reader as its a "live" element. And its content will be read if nothing else occurs (polite) and in an atomic way, by not cutting a message. This log have to be hidden to the normal users (of course). The new messages coming from the server (using Comet for example) will populate the #chat and also the #log. And it works (tested with Firefox 3 and Orca).

Find a demo here (that fakes server messages coming from time to time) or watch the video (make sure the sound is turned up).

My conclusion on this is that it’s not because your product has a very advanced feature that you cannot, in theory, offers it the maximum of users regarding their capabilities or disabilities. And in some cases isn’t a huge overhead. And ARIA will be applied to SVG has well, if you’re doing RIA using that technology.

Depuis mes débuts sérieux dans la conception de pages internet, le jour où j’ai abandonné Dreamweaver 3 et son lot de cracks pour HTMLkit (à l’époque), l’accessibilité fait partie des points inhérents aux web, des non pas contraintes, mais devoirs moraux qui imcombent au développeur. Ce petit truc qu’il ne doit pas oublier, cette dose d’empathie. Les sites comme A List Apart (donc Pompage faisait régulièrement l’écho), Digital Web et relayé par les bloggeurs ont depuis un peu changé de discours, le combat contre les frames et autres mésusage des tableaux HTML semblant de manière générale gagné. La mauvaise accessibilité des mises en forme à base de table était un argument fort, on a jeté les tables et pas forcément amélioré la dite accessibilité.

Les petits soucis d’autrefois ne sont-ils pas aujourd’hui plus important depuis qu’on se repose sur ce système fortement informatisé, de plus en plus. Ne pas créer de barrière artificielle, virtuelle à l’image d’un escalier que ne pourrait emprunter aisément une personne âgée; voire pas du tout pour quelqu’un n’ayant plus l’usage de ses jambes. Quand Internet passe d’une solution alternative, à une solution principale, essentielle ou parfois unique, le point d’être ouvert à toutes et à tous prend de l’importance et ne doit pas être relêgué aux “nice to have”.

ARIA vient s’ajouter aux recommandations du W3C pour répondre au flou qui entoure la complexisation de ce que nous faisons avec le web aujourd’hui. Il se destine aux applications riches (RIA en anglais) comme le dit si bien son acronyme. Par exemple, la métaphore visuelle de l’astérisque pour représenter un champ de formulaire obligatoire peut être fait avec un attribut ARIA: aria-required="true".

Sans :

<label for="f">Nom*:</label>
<input type="text" id="f" name="name">

Avec :

<label for="f">Nom*:</label>
<input type="text" id="f" name="name" aria-required="true">

Qui va être lu de la sorte, par exemple: “Nom*, required, edit”

J’aime bien cette version là :

<label for="f">Nom<span> (requis)</span>:</label>
<input type="text" id="f" name="name">

Et, le champ texte est remplacé par une image d’astérisque via CSS (avec un truc aussi laid que : display:-moz-inline-box;display:inline-block;). Et pour joindre les deux, il est possible de faire ceci :

<label for="f">Nom<span aria-hidden="true"> (requis)</span>:</label>
<input type="text" id="f" name="name" aria-required="true">

Bref, ça devient tordu, mais si pas d’information est à éviter absolument, une duplication est également mauvaise. NB: Orca gère le aria-hidden mais pas aria-required par exemple, le résultat n’est pas celui désiré donc, dommage.

Dans la partie anglaise de ce post, trouvez un exemple plus avancé de l’usage des régions vivantes (live) dans le cadre d’un chat où il est possible d’approcher le comportement d’un application native telle que Pidgin (autrefois connue sous le nom de Gaim).

En conclusion, appliquer ARIA ne demande pas forcément un gros effort en terme de modifications. Ça demande un investissement certain en tests néanmoins. Et ajoute une quatrième composante aux : contenu, mise en forme et comportement, qui serait rôles ou responsabilité, pouvant être fait entièrement avec JavaScript.

Comet using event-source

Yoan BlancTue 16 September 2008, , ,

One month ago, I painfully managed to show the possibilities that offers the upcoming html5 tag: event-source (Server-sent event), during the Zürich Webtuesday of August. But it ended up being more confusing than really interesting. I need to practice hardly my presentation skills. I’ll try to fix that here.

Event-source is a way to have a continuous streaming data from the server with the minimum overhead for the front-end developer. It’s not new at all but the motivations of having Comet-based applications and the growing interests around HTML5 can influence us to follow that direction. Event-source is part of the many communication capabilities that will potentially (reading “one day”) offer HTML5.

First of all, test it (the Opera browser is required), they are two examples:

Both of them are adaptations of old plays, the first one was using an hidden iframe and the second the XHR long-polling.

Beside the fact that using event-source is very trivial, basically listening to a DOM event. It has other advantages over the existing solutions:

  • Latency, using XHR long-polling forces you to reconnect once an event has been sent. It means that if you have events that occurs very quickly some of them will have to wait and come as a batch with the next call. I cannot measure the implication from a server perspective, but can imagine that opening a connection has a cost that isn’t negligible and something simply not feasible due to a high flow of message.
  • It’s not a hack, so you can have forward compatibility.
  • Simplicity, the language is quite simple, you’ve got a key (event name) and value (message or data). Which is how many web application works these days with Memcached, CouchDB or Amazon’s Dynamo.

Its only (and huge) disadvantage is that it isn’t part of your browser yet. Opera, who created the first specification for this, supports it; but — as the specs aren’t finished — this is afaik their early version that is implemented.

Opera has an example using Python that is two years old now and still working. The code in the example shows a time.sleep and this is something — I think — is bad. I’d like to be able to do that with Twisted or Eventlet, but at the moment, I’ll stick with Mochiweb and Erlang. That introduces outputting chunked content from Mochiweb that is quite interesting too.

Basically, the main code remains the same (here simplified).

case Req:get(method) of
 Method when Method =:= ’GET’; Method =:= ’HEAD’ ->
  case Path of
   "chat" ->
    Room = get_the_room(),
    Room ! {self(), subscribe},
    receive
     subscribed ->
      Response = Req:respond({
       200, [{"Content-Type", "application/x-dom-event-stream; charset=utf-8"}], chunked}),
       wait_for_a_message(Response, ?TIMEOUT),
      after 1000 ->
       true
      end,
    
    Room ! {self(), unsubscribe};
% [...]

Room is the process that handles the messages. With this very simple chat, the system is stateless regarding to the clients, the client don’t live through reconnection which can lead to losing some messages, but I don’t care for now. So, you subscribe to the Room, wait for being correctly subscribed and starts waiting for messages.

Starting means here, displaying the HTTP headers, so starting the response with Req:respond, status is 200, one specific header for event-source and chunked because this is what we want. And then let’s wait for incoming messages.

wait_for_a_message(Response, Timer) when Timer < 0 ->
 Response:write_chunk("");

wait_for_a_message(Response, Timer) ->
 receive Message ->
  Response:write_chunk(lists:flatten(io_lib:format("Event: ~s~ndata: ~s~n~n", ["message", Message]))),
  wait_for_a_message(Response, Timer)
 after ?PROXY_TIMEOUT ->
  %% write a comment (every 15s.)
  Response:write_chunk(lists:flatten(io_lib:format(":~n", []))),
  wait_for_a_message(Response, Timer - ?PROXY_TIMEOUT)
 end.

Basically, wait for a message, display it or display a comment to avoid being disconnected by a web proxy and start waiting again. To avoid waiting forever, there is also another timeout. I’m sure we are awake of the client closing the connection. And when the timeout is over, we can close the connection by sending an empty message. If I know that the one for the proxy is highly recommended (or mandatory), the other one is more a magical number I put here.

% Global Timeout
-define(TIMEOUT, 150000).
% Apache Timeout is 15s,
% many proxies act the same way.
-define(PROXY_TIMEOUT, 15000).

The output looks like you can find on the examples:

Event: message
data: foo

Event: message
data: bar

I’d like to see a cross-browser compatible implementation of event-source using the existing tools we have, like XHR (I don’t anything else actually). It’ll be a hack anyway, but maybe a necessary one to make the transition possible. The example I made had two entry points, one for event-source to get the events and the other for XHR to send the events.

Il y a un peu plus d’un mois, j’ai difficilement tenté d’introduire lors du Webtuesday zürichois le tag event-source (Source-sent event). Existant au sein du navigateur Opera, où Ian Hickson y a esquissé la première spécification, il est possible de s’en servir dès aujourd’hui (depuis un peu plus de deux en réalité).

Event-source est une balise HTML (plus des points d’entrée JavaScript) qui permet de récupérer en continu des données depuis un serveur, une page qui se chargerait de manière infinie. C’est tout simplement l’idée de pousser du contenu vers le client, nommé Comet par opposition à Ajax où le client (navigateur internet) demande au besoin de l’information au serveur web. Si l’application exemple de facto, unique et omniprésente est le chat, les besoins de transférer de l’information de manière continue par rapport à en faire la demande de manière temporisée se répandent de plus en plus.

À mon sens, il y a de nombreux avantage de partir avec un système fonctionnant sur cette architecture (le tag et la logique sous-jacente) :

  • latence, les données arrivent au fur et à mesure. Le long-polling, à plusieurs reprise présenté ici implique une reconnexion dès qu’une donnée est arrivée. Ce qui est une latence parfois non désirée, pour un site boursier nécessitant des mises à jour très rapide, tout comme, j’imagine, provoque un travail supplémentaire pour le serveur de réouvrir n connexions et réinitialiser autant d’état lors des reconnexions;
  • compatilibilité ascendante, si HTML5 est prévu pour 2022 (en souhaitant que ça soit une blague), autant bâtir un système sur une solution vouée à devenir standard plutôt qu’un hack destiné à s’effacer;
  • simplicité, oui, c’est très simple. Un système clé/valeur (comme memcache) auquel on souscrit. On s’inscrit à une clé et récupère la valeur sous forme de texte (qui peut représenter du JSON par exemple).

Le problème avec ceci actuellement est double : seul Opera supporte cet balise, et les spécifications ne sont pas terminées donc, c’est une version non-finale qui est actuellement disponible. Avec des pincettes donc.

Je repris les expérimentations faites autour de Comet et les ai adaptées pour utiliser le tag event-source. La première utilise web.py 0.3 et la seconde utilise MochiWeb. Je vous laisse le soin de passer à la version anglaise qui contient des détails plus techniquement croustillants.

Imaginons maintenant les possibilités de ce type de streaming. Des sites comme FriendFeed semblent arriver aux limites des APIs existantes, et cherchent des alternatives comme PubSub de XMPP (utilisé par Twitter ) et Sup (FriendFeed). Il y a également le système de SixApart : Stream Update, basé sur Atom. Ces systèmes ont des détracteurs car apparemment trop éloignés de HTTP et des architectures à saveurs REST. Si le chat est bien évidemment l’exemple plus que répandu, il peut être étendu à du chat plus complexe comme IRC, du jeu en ligne, système affichant des informations en temps réel. Partout là où manquer un message n’est pas important. Il reste à faire un système de confirmation de message si chaque message est important. Le “protocole” Bayeux a peut-être ce méchanisme là, qui n’est pas imposé d’ailleurs.

Quelqu’un a une idée de projet à réaliser ? Il ne manque que la volonté, au fond.

About

meYoan Blanc is a web developer that lives in Lausanne (rue Couchirard 15, 1004 Switzerland) worked for Yahoo! and comes from La Chaux-de-Fonds. This web site is for this weblog, a playground for random stuffs and can help keepingmeconnected with some friends out there.

Get my vCard or contact me by phone (+41 21 625 82 09) or email ().

Misc

RSS, list.blogug.ch

This site reflects only my opinion and is not affiliated with anyone else.

copyright 2006-2008 — doSimple.ch