css
Jul 21, 2010
Migliorare l'usabilità dei link interni in TinyMCE
Analisi di collective.tinymceplugins.advfilelinks, un'alternativa al plugin di TinyMCE per i link interni a Plone che permette di gestire in modo differente i link a file del sito.
La Regione Emilia Romagna sta lavorando alacremente al miglioramento dell'accessibilità e dell'usabilità di Plone.
Dato che il futuro dell'editor WYSIWYG in Plone non è più Kupu (difficilmente personalizzabile e non troppo supportato) ma TinyMCE, già da tempo la scelta è stata di passare a TinyMCE anche nella versione 3 di Plone, usata in vari siti regionali.
Migliorare TinyMCE è più semplice che Kupu e lo dimostra come è stato possibile da parte nostra aumentarne le funzionalità per venire incontro ad alcune delle richieste della Legge Stanca (modifiche di cui si è discusso in un altro post, e ora integrate nella release ufficiale già dalla versione 1.1rc9); Altro particolare: trovo importante che questo editor esista anche come progetto indipendente.
Altre novità: la gestione dei link
Una richiesta recente per aumentare l'usabilità dei documenti è stata la seguente:
Modificare Plone in modo che i link interni, se fatti a contenuto di tipo File, mostrino l'icona del tipo di contenuto e la dimensione del file stesso
Una simile modifica aumenta l'usabilità generale della pagina, nonché impatta col Requisito 19 della Legge Stanca.
Dopo una prima analisi è risultato chiaro come fosse necessario scrivere un nuovo plugin per TinyMCE.
Come funziona collective.tinymceplugins.advfilelinks?
Il prodotto rilasciato fornisce il minimo delle modifiche possibili a TinyMCE (ma non minime quanto avrei voluto... ne parliamo dopo). Si tratta di un un plugin aggiuntivo (e per fortuna la presenza di plugin è prevista non solo dall'editor ma anche dalla sua configurazione di Plone) che sostituisce quello predefinito di Plone per i link interni (dal nome autoesplicativo plonelink).
Dopo un'analisi attenta di come poter ottenere le funzionalità richieste e della flessibilità delle API di TinyMCE, su indicazione della Regione stessa abbiamo preso la seguente strada, forse un po' limitata ma di minimo impatto sullo sviluppo e con una resa eccezionale se il browser è aggiornato:
- I link a file acquisiscono un nuovo attributo type (previsto dallo standard HTML anche se poco conosciuto) ed viene fornito un CSS aggiuntivo contenente varie regole per fornire l'icona.
Esempio:
a[type='application/pdf'] { background: url(pdf.png) no-repeat 0 50%; padding-left: 20px; }Questo tipo di regola CSS ha un buon supporto (da Internet Explorer 7 in poi). - La dimensione del file è prima di tutto inserita nel title del link (che normalmente il plugin originale non fornisce) ma un buon effetto è ottenuto associando una ulteriore regola CSS:
a.internal-link-tofile:after { content: " ("attr(title)")"; }Questa magica regola CSS (fa parte dello standard CSS 2, per quanto Internet Explorer la supporti solo dalla versione 8 in poi) inserisce del testo aggiuntivo dopo i link con classe internal-link-tofile.
Il contenuto di questo testo è preso dall'attributo title, ma vi vengono aggiunte delle parentesi. Ovviamente questa classe CSS aggiuntiva è inserita dal nostro plugin in aggiunta alla già nota internal-link.
L'ultima funzionalità è forse la più interessante e per quanto il metodo usato sia davvero poco invasivo e l'effetto finale a dir poco bello, il limite ad avere Internet Explorer 8 è ancora grande.
E' comunque sopportabile? Sì, dato che l'attributo title rimane comunque disponibile agli utenti (e agli Screen Reader) in tutti i casi.

Note tecniche di estendibilità
TinyMCE per Plone sfrutta chiamate AJAX per richiedere al server informazioni sui contenuti. Come sempre le modifiche lato server sono minime e perfettamente integrate con quanto Plone già fornisce.
E' bastato fornire un nuovo adapter.
<adapter
for="Products.ATContentTypes.interface.IATFile"
provides="Products.TinyMCE.adapters.interfaces.JSONDetails.IJSONDetails"
factory=".adapters.JSONDetails"
/>
Grazie alla ZCA, questo adapter aggiuntivo interviene solo per i contenuti di tipo File o sottotipi (a volte ho l'impressione che senza adapter i plonisti non vivrebbero più!).
I problemi maggiori sono lato client... L'idea sarebbe come sempre estendere e non sovrascrivere. In un mondo perfetto questo plugin si sarebbe dovuto integrare con quello preesistente, sfruttandone tutto il codice presente.
Non mi è ancora chiaro se questo non è stato possibile per limiti miei, del plugin stesso, o di TinyMCE, ma il risultato per quanto funzionante è anche una copia di molti dei file originali (una forma di branch del plugin)... probabilmente non dormirò di notte per aver dovuto copiare i file di lingua... ma dopo tutto è una versione alpha!
Il limite maggiore di TinyMCE attualmente è che non usa jQuery (per quanto ci sia un progetto che integra jQuery e TinyMCE) e soprattutto che non c'è uso di eventi Javascript.
Sarebbe stato bello (ma che dico bello! Utile) se al click del mouse sul pulsante radio che seleziona un file piuttosto che un qualunque altro documento a cui associare il link, venisse lanciato un evento Javascript... evento al quale un buon plugin per jQuery avrebbe potuto reagire per eseguire azioni...
Per ora questo non pare possibile, ma sarebbe un buon passo avanti per TinyMCE.
Nota sul namespace
Sono rimasto colpito nel vedere come sulla collective ci siano così pochi plugin the TinyMCE (l'unica eccezione pare essere collective.tinymcetiles). Ci sono state sanguinose discussioni in passato sull'uso di namespace a 2 o 3 livelli (ne ricordo una completa e interessante). In questo caso l'uso dei 3 livelli mi è parso opportuno.
Spero che in futuro altri contribuiscano al gruppo di plugin collective.tinymceplugins e figli!
Riferimenti
Jul 08, 2010
Scripted CSS Injection (or whatever better name you can find for this technique)
While trying to close a request for one of our customer for obtaining a random image portlet I tested an alternative way to deliver CSS. Using Javascript.
When Web pages load and run things
Let's start with CSS. Browsers load HTML source from the Web. Inside the page you will find resources that are CSS file. Immediately the resource is loaded and the rules inside are applied to your HTML.
Now switch to Javascript resources. For Javascript... it's the same. The Javascript code is executed as soon as it is found in the page...
...but for this reason, when we need to act using Javascript on an already loaded DOM, we rely onto Javascript events.
We read immediately the code, but the execution is postponed later, when the page is fully loaded.
As the use of jQuery became standard for those tasks (especially in Plone) we always use something like this:
jq(document).ready(function() {
// do something
});
When this lead to problems
Although we have really no choice, there are some cases where this "postpone things" is not perfect: when we need to apply (using Javascript) CSS classes on page elements at page load time.
But we can't avoid making those actions when page is loaded.
If we don't rely on onload event, we have no ready DOM to traverse. So we can't load and change a DOM node if the page is not fully loaded (even if we put the Javascript script after the HTML that define the node).
<html>
<body>
<div id="foo">Hello world</div>
<script type="text/javascript">
<!--
var foo = document.getElementById("foo");
alert(foo.innerHTML);
// -->
</script>
</body>
</html>
The code above is bad, even if you are using or not jQuery... So we really need to wait for the moment when DOM is ready. You can't act of the page DOM before it is fully loaded.
However: what is the problem applying CSS style when the DOM is loaded?
The nasty effect can be a visual flip.
The page in the browser show the DOM node with the original CSS style, then after some time (that can be not so brief sometimes if the page is full of elements and heavy scripts) the Javascript engine run your code, and the node is changed: your new CSS class or your new scripted style is applied.
<html>
<head>
<style type="text/css">
#foo {
background-color: red;
}
</style>
<script type="text/javascript">
<!--
window.onload = function() {
... MANY OTHER EXPENSIVE OPERATIONS
var foo = document.getElementById("foo");
alert(foo.innerHTML);
}
// -->
</script>
</head>
<body>
<div id="foo">Hello world</div>
... A LOT OF MANY AND MANY HTML NODES
<script type="text/javscript">
<!--
var foo = document.getElementById("foo");
alert(foo.innerHTML);
// -->
</script>
</body>
</html>
A practical example
A customer ask us to develop a Plone portlet that:
- show some random images when the page is load
- works behind a reverse proxy (Varnish)
- works with Javascript disabled (accessibility and graceful degradation)
Step 1
Varnish is caching all our resource, images and also HTML for every page. We can't (and don't want) change this.
How to cache everything but some little images inside a portlet?
The idea is to use Javascript for performing AJAX request for this portlet and obtain a structure of data. The cache of this kind of request can be avoided easily.
Step 2
So we are able to load an HTML for the portlet without images then, when the DOM is ready, we can populate the portlet waiting for the AJAX call to the server. For some time the visitor see and empty portlet that magically begin load images. The effect is pleasant (at least... it's not annoying).
But we can't!
The portlet must work also with disabled Javascript... So we must load random images also when the page is loaded.
NB: if the visitor use a browser with Javascript disabled, we can only give him some random pre-loaded images, but we can't prevent Varnish cache of the whole page. Reloading the same page will show him the same images for some minutes. This is acceptable for us (and for the customer!).
Step 3
The final result is to load the first "static" images in the portlet itself, then use Javascript as described at step 1: changing those images with new ones obtained from AJAX call.
This lead to the ugly visual flip effect I talked above.
I can't explain why (this is not my work), but see an empty section that is filled after a little delay is not ugly... instead seeing a set of images that suddenly change to other is... bothersome!
Step 4?
Ok, so we can simply load static images hidden by some CSS class, then using Javascript we can show them only after the AJAX call and...
Opss!
But in this way we don't see any image when Javascript is disabled!
Ok... step 4 aborted.
Scripted CSS Injection
The perfect world is the one where the step 4 is performed, but only with Javascript enabled.
I need a CSS that is loaded early like all other CSS in the page (so its style is applied immediately to the page) but only when Javascript is enabled.
I found a way to do this, but surfing the web I was not able to find other example like this one. So I called this approach Scripted CSS Injection (SCI)... maybe someone can point me to other original name or example?
However... how this works? Simply generating the additional CSS... with Javascript!
For this we use the standard window.write Javascript API. The window.write command is used commonly to write HTML inside windows (is more common to use it in popup windows for generating the contained HTML from scratch).
The additional Javascript is load in the page head section and it doesn't wait for DOM load. The one in our product is only one line:
document.write('<style type="text/css">.hideFlag img {display: none}</style>');
As I said at the beginning, Javascript is interpreted as CSS, so immediately when found in the page.
The browser will add to HTML the style node immediatly.
What is nice of SCI approach is obvious: a browser with no Javascript support can't add the CSS rule to the page!
Fairytale gone well
This technique finally lead us to a portlet that:
- will show cached images if without Javascript support, but images are still random (chosen server side and changed with some delay)
- will show random (and not cachable) images client side if Javascript is enabled
- No ugly visual flip effects. With Javascript enabled static images are loaded hidden, then new dynamic ones are taken from the server and show. Thanks to SCI approach.
For more info, check the code of auslfe.portlet.multimedia.
May 03, 2010
No more "display:none" CSS rules!
Plone give us the right way to hide elements from the HTML page! Just use it... but what about jQuery?
It's not a news that accessibility is an important target of Plone... and Plone knows that CSS rules that use "display: none" are not readable by screen readers. However too often the display:none rules is used in themes, add-ons...
The problem is that this behavior is not so know outside the Plone core. Developers sometimes thinks that something that is hidden from the screen but present in HTML is accessible using a screen reader.
This is false.
How the screen reader works?
I'm not a real expert about it, but here what I learned.
When the page is loaded, the screen reader make a "screen-shot" of it and works on this. So elements that are hidden... for everyone!
So:
- Use display:none if you really want something in HTML that no-one can read.
- Do it like Plone does... apply the hiddenStructure class to your HTML element when you want something that can be accessible but not visible on you computer screen
What about Javascript/jQuery?
You like the jQuery .hide() and .show() features like me?
Well... keep in mind what you read some lines above... You use some .hide() call at load time? You use .hide() when clicking some links or buttons?
All this is not accessible...
Again, you need to think about using CSS given by Plone, so you must rely on the .addClass("hiddenStructure") and .removeClass("hiddenStructure") methods...
If you prefer give some new features to jQuery, you can also do something like this:
jQuery.fn.ploneHide = function() {
return this.each(function() {
jQuery(this).addClass("hiddenStructure");
});
}
jQuery.fn.ploneShow = function() {
return this.each(function() {
var e = jQuery(this);
if (e.is(":hidden")) e.show();
e.removeClass("hiddenStructure");
});
}
After this, you can rely on some new jQuery features!
jq(".documentByLine").ploneHide();

