Nell'ultimo anno, prima per lavoro e in questo periodo per esperimenti personali, mi sto addentrando nella programmazione Javascript, e l'ho fatto scalando la parete più ripida della montagna: contentEditable.
Ho deciso quindi di riassumere qui le varie idosincrasie che ho trovato, sperando che mi servano in futuro per evitare di sbattere di nuovo la testa a sangue contro il muro. Per tutti gli esperimenti ho usato Firefox (tra la 8 e la 10, più o meno)
Preparare l'ambiente
Ci sono due modi per usare contentEditable: definire tutto il documento contentEditable (di solito si usa con un iframe), o definire solo un elemento (la strada che ho seguito io). Nel primo caso basta, da Javascript:
document.contentEditable = true;
Nel secondo basta creare un elemento HTML con la proprietà contenteditable:
<article contenteditable="true"></article>
Fatto questo, io personalmente imposto tre proprietà:
document.execCommand("useCSS", false, true);
document.execCommand("styleWithCSS", false, false);
document.execCommand("enableObjectResizing", false, false);
La prima serve a usare <B>
e <I>
per fare grassetto e corsivo in Firefox, mentre Explorer (da quel
che leggo) usa <STRONG>
e <EM>
. Se non la si specifica, Firefox riesce a fare peggio che non seguire
la semantica di HTML: usa <span style=”font-weight: bold;”></span>
e <span style=”font-style: italic;”></span>
La seconda fa la stessa cosa, ma una delle due è deprecata. Per compatibilità io le uso entrambi.
La terza serve ad evitare che, se ci sono oggetti come <img>
o simili, l'utente possa
ridimensionarli trascinandoli. Si può anche non specificarla, ma io preferisco controllare cosa fa
l'utente tramite plugin jQuery che controllano gli spostamenti e i ridimensionamenti.
La cosa importante da notare è che TUTTI i comandi dati tramite execCommand() vanno eseguiti DOPO che c'è un elemento con contentEditable presente e visibile nel DOM. Se state creando l'elemento da Javascript, e fate (con jQuery)
var $el = $('<article />').attr('contenteditable', true');
document.execCommand("useCSS", false, true);
$('body').append($el);
Riceverete una bella eccezione nella console di Firefox. Basta spostare l'execCommand dopo l'append.
Non basta un contentEditable vuoto
Naturalmente non basta un <article contenteditable=”true”></article>
, perché, come tutti gli
elementi senza contenuto, le sue dimensioni sono 0x0, quindi è invisibile e soprattutto
“incliccabile”, e perciò non c'è modo di scriverci dentro. Basta aggiungerci un figlio. Alcuni ci
mettono un <br />
, ma io preferisco un <p>
, che però ha gli stessi problemi, quindi la sintassi
completa è:
<article contenteditable="true">
<p>
<br />
</p>
</article>
Perché questa tiritera? Perché Firefox, se state scrivendo dentro un <p>
, quando premete Invio
chiuderà automaticamente il <p>
e ne aprirà un altro identico. In qualsiasi punto siate. Se siete
fuori da un <p>
, inserirà semplicemente un <br />
, con buona pace della semantica (e per la gioia
dei cialtroni che fanno spaziature verticali premendo Invio n volte).
Ma ancora non basta! Ma cosa vuole??
Se avete predisposto tutto il suddetto, e avere fatto la vostra toolbar (magari in un prossimo articolo vedremo come) con la possibilità di inserire grassetti, corsivi, liste, ecc., vi scontrerete con un problema assurdo: Se tentate di rendere “lista” il primo elemento del contentEditable, Firefox solleva un'eccezione. Bold e Italic funzionano perfettamente, solo le liste (e gli allineamenti, e forse qualcos'altro che non ho ancora scoperto) danno errore. È un bug di Firefox, presente fin dalla 2.0, pare. Io l'ho aggirato così:
<article contenteditable="true">
<p></p>
<p>
<br />
</p>
</article>
Con un <p>
vuoto (quindi dimensioni 0x0, quindi incliccabile) prima del contenuto vero. Brutto,
ma funziona. Poi il codice si ripulisce lato server, perché ha TANTO bisogno di essere ripulito.