Html5 based

  • 2,633 views
Uploaded on

guida presa da HTML.IT ....

guida presa da HTML.IT ....

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
2,633
On Slideshare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
0
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. IntroduzioneUna guida operativaAffrontare un tema vasto come quello dellHTML5 spaventa sempre un po, soprattutto quandolobiettivo è quello di abbracciare lintera tecnologia sottostante le specifiche proponendo al contempounopera che sia fruibile e divertente da leggere. Il primo passo che abbiamo deciso di compiere nellastesura di questo progetto è stato individuare il target di lettori ai quali la guida vorrebbe rivolgersi.Abbiamo allora identificato da un lato un gruppo di sviluppatori interessati alla consultazione dispecifiche referenze del linguaggio, dallaltro un insieme di lettori desiderosi di informarsi a tuttotondo sulle novità offerte dallHTML5. A questa commistione di interessi si aggiunge una naturalesegmentazione della guida secondo i due temi che maggiormente permeano le specifiche: il nuovoapproccio semantico nella creazione di pagine web e il ricco set di API reso disponibile.Il percorso si snoda in modo organico tra le due macro-sezioni alternando lezioni di stampodivulgativo, ottime per avere una visione di insieme della tematica trattata, a percorsi verticalicostruiti attorno a funzionalità specifiche. Non sono previsti articoli introduttivi alla sintassi dellinguaggio HTML e nemmeno approfondimenti su elementi o API già presenti nelle versioni precedenti,a meno che questi non abbiano subito un cambio radicale; se fosse necessario recuperareinformazioni su tali aspetti rimandiamo alla lettura della guida HTML 4(http://xhtml.html.it/guide/leggi/51/guida-html/) redatta da Wolfgang Cecchin.I progetti guidaPer questa guida abbiamo deciso di combinare i tanti piccoli esempi dedicati ad ogni lezione in unvero e proprio progetto che sappia anche mostrare come le singole funzionalità HTML5 lavoranoinsieme.In realtà i progetti sono due, come due gli aspetti principali di questa specifica: al termine dellelezioni legate al nuovo supporto semantico dellHTML5 la combinazione dei vari esempi mostrati daràvita ad untemplate per blog studiato per trarre vantaggio da elementi come <section> e<article>, dai nuovi content model e dalle novità in materia di form. La parte incentrata sulle APIdedicate allo sviluppo di applicazioni web invece includerà tutti gli elementi necessari alla stesura diuna lavagna virtuale sulla quale si potranno tracciare linee utilizzando il mouse e che darà lapossibilità di salvare in locale le opere create.Chiaramente tale scelta è stata implementata in modo da non pregiudicare lindipendenza dellesingole lezioni ma con lidea di suggellare un ulteriore filo conduttore allinterno dellopera.Figura 1 - Anteprima del template per blog in HTML5 (click per ingrandire)
  • 2. (http://www.html.it/guide/esempi/html5/imgs/lezione_1/blog_preview.png)Alcuni prerequisitiNella prossima lezione ci interesseremo con maggior attenzione alla timeline ufficiale HTML5, per orabasti sapere che la data di accettazione delle specifiche come standard W3C è ancorasufficientemente lontana. Nonostante questo, buona parte di quanto verrà trattato in questa guida ègià disponibile sulla grande maggioranza dei browser e, come vedremo, alcuni aspetti del linguaggiosono da tempo in produzione su portali di notevoli dimensioni, come youtube.com(http://www.youtube.com/html5) o vimeo.com (http://vimeo.com/blog:268).Esistono tuttavia ampie porzioni delle specifiche che, perché meno strategiche, di più difficileimplementazione o meno mature, sono ad oggi supportate in modo superficiale e disomogeneo; perpoter beneficiare al massimo delle demo e degli esempi anche per elementi o API che ricadono inquesta categoria si consiglia quindi di dotarsi di un browser che utilizzi WebKit come layout engine inquanto dotato del più ampio supporto HTML5 ad oggi disponibile sia per le parti della specifica ormaiconsolidate sia per quelle al momento più sperimentali.In particolare, tutto il codice di questa guida è stato sviluppato e testato usando la ‘Nightly Build diChromium, cioè la versione speciale per fini di sviluppo che contiene ogni feature ad oggiimplementata, per quanto sperimentale esso sia. La pagina per il download, disponibile per i principalisistemi operativi, è raggiungibile allindirizzo http://build.chromium.org/f/chromium/snapshots/(http://build.chromium.org/f/chromium/snapshots/) seguendo il link nominato come il propriosistema operativo e successivamente la cartella recante il numero più alto tra i presenti.Tabella della compatibilità sui browserSe Chromium, lo accennavamo, garantisce ad oggi il supporto più ampio alle funzionalità previstenella specifica e in via di definizione presso il W3C e il WHATWG, la maggior parte dei browsercommerciali più diffusi, con ritmi e tempi diversi, si sta adeguando. Internet Explorer 9 e Firefox 5,rilasciati nella primavera di quest’anno, condividono infatti un ottimo supporto a queste specifiche.
  • 3. Lo stato dellarte relativamente al supporto HTML5 lo abbiamo tracciato in questa tabella dicompatibilità (http://www.html.it/guide/esempi/html5/tabella_supporto/tabella.html) che sarà via viaaggiornata con lestendersi del supporto alle feature che attualmente non sono supportate. Estrattidella tabella sono inseriti anche a corredo delle lezioni dedicate a ciascun elemento.Mappa della guidaNellimmagine seguenti è riassunta lintera struttura dellopera mettendo in evidenza la posizione dellesingole lezioni rispetto al contenuto globale con lobiettivo di fornire una panoramica esauriente suitemi che verranno trattati.Ai nastri di partenza!Figura 2 - Mappa della guida (click per ingrandire)(http://www.html.it/guide/esempi/html5/imgs/lezione_1/2.jpg)Bene, con questo può definirsi conclusa questa necessaria sezione introduttiva, la prossima lezioneaffronterà la travagliata storia che ha caratterizzato la definizione di queste specifiche, con un piccoloma sentito cameo anche da parte dellXHTML2. Da HTML 4 ad HTML5Un po di storiaSiete curiosi di sapere come tutto è nato? Venerdì 4 giugno 2004, in una notte buia e tempestosa, IanHickson annuncia la creazione del gruppo di ricerca WHAT (http://www.whatwg.org/), acronimo diWeb Hypertext Application Technology in un sintetico ma ricco messaggio(http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2004-June/000005.html).Lobiettivo del gruppo è quello di elaborare specifiche per aiutare lo sviluppo di un web più orientatoalle applicazioni che ai documenti; tra i sottoscrittori di questa iniziativa si annoverano aziende del
  • 4. calibro di Apple, Mozilla e Opera. Questa piccolo scisma dal W3C è determinato dal disaccordo inmerito alla rotta decisa dal consorzio durante un famoso convegno del 2004 dove, per un pugno divoti, prevalse la linea orientata ai documenti di XHTML2."XHTML 2.0 considered harmful (http://lists.w3.org/Archives/Public/www-html/2003Jan/0123.html)"è il titolo di un messaggio inviato alla mailing list ufficiale del W3C datato 14 gennaio 2003 che benriassume i sentimenti contrastanti che allepoca si respiravano in merito a queste specifiche. Laprincipale causa di perplessità è da ricercarsi nella decisione azzardata di non mantenere la retro-compatibilità con la versione 1.1 eliminando alcuni tag e imponendo agli sviluppatori web uncontrollo rigoroso nella creazione delle pagine, pena lo stop del processo di parsing e lavisualizzazione a schermo degli errori di interpretazione. Nei due anni successivi i gruppi XHTML2 eWHAT proseguono i lavori sulle proprie specifiche in modo indipendente e parallelo, sollevando dubbie confusione sia da parte dei produttori di browser che degli sviluppatori web. Emblematico in talsenso è un articolo firmato da Edd Dumbill nel dicembre 2005 intitolato The future of HTML(http://www.ibm.com/developerworks/xml/library/x-futhtml1/). Il 27 ottobre 2006 in un post sulproprio blog intitolato Reinventing HTML (http://dig.csail.mit.edu/breadcrumbs/archive/2006/10/27),Tim Berners-Lee annuncia la volontà di creare un nuovo gruppo di ricerca che strizzi locchio al WHATe ammette alcuni sbagli commessi seguendo la filosofia XHTML2: Some things are clearer with hindsight of several years. It is necessary to evolve HTML incrementally. The attempt to get the world to switch to XML, including quotes around attribute values and slashes in empty tags and namespaces all at once didnt work. The large HTML-generating public did not move, largely because the browsers didnt complain. Some large communities did shift and are enjoying the fruits of well-formed systems, but not all. It is important to maintain HTML incrementally, as well as continuing a transition to well- formed world, and developing more power in that world. Tim Berners-Lee.Dovranno passare quasi altri due anni di competizione tra le due specifiche, questa volta entrambeinterne al W3C, prima che nel luglio del 2009 lo stesso Tim sancisca di non voler riconfermare ilgruppo XHTML2 per lanno successivo preferendo di fatto la direzione intrapresa dallHTML5.Frattanto il gruppo di ricerca, formato da una commistione di elementi del W3C e del WHAT, sotto laguida di Ian Hickson, è giunto alla 4° versione delle specifiche (http://www.whatwg.org/specs/web-apps/current-work/multipage/).Nonostante il continuo e solerte lavoro e il grande intervallo di tempo speso nella stesura di questodocumento, i passi residui necessari ad eleggere questa tecnologia al rango di W3C Reccomandation,relegandola così tra gli standard riconosciuti, sono ancora molti, al punto che si prevede diraggiungere lagognato traguardo soltanto attorno al 2020.Ricordiamo però che il consorzio si riferisce sempre allintero universo inscritto nelle specifiche mentrealcune feature ritenute peculiari ed importanti, ad esempio il tag <video>, sono già implementate datempo dalla totalità (o quasi) dei browser in commercio.Che cosè lHTML5?Domanda semplice solo allapparenza; siamo sicuramente di fronte alla quinta revisione dellespecifiche HTML ma anche di un vastissimo elenco di funzionalità che si sviluppano attorno al temadel linguaggio di markup: cerchiamo quindi di fare un po di ordine.Per prima cosa è importante ricordare che, anche in virtù della storia della sua nascita, allinternodellHTML5 convivono in armonia due anime: la prima, che raccoglie leredità semantica dellXHTML2,e la seconda che invece deriva dallo sforzo di aiutare lo sviluppo di applicazioni Web. Il risultato diquesto mix di intenti è più articolato di quanto si immagini; in prima istanza si assiste ad una
  • 5. evoluzione del modello di markup, che non solo si amplia per accogliere nuovi elementi, mamodifica in modo sensibile anche le basi della propria sintassi e le regole per la disposizione deicontenuti sulla pagina. A questo segue un rinvigorimento delle API JavaScript che vengonoestese per supportare tutte le funzionalità di cui una applicazione moderna potrebbe aver bisogno: salvare informazioni sul device dellutente; accedere allapplicazione anche in assenza di una connessione Web; comunicare in modo bidirezionale sia con il server sia con altre applicazioni; eseguire operazioni in background; pilotare flussi multimediali (video, audio); editare contenuti anche complessi, come documenti di testo; pilotare lo storico della navigazione; usare metafore di interazione tipiche di applicazioni desktop, come il drag and drop; generare grafica 2D in tempo reale; generare grafica 3D in tempo reale; accedere e manipolare informazioni generate in tempo reale dall’utente attraverso sensori multimediali quali microfono e webcam.Anche laspetto semantico a contorno del markup non è dimenticato; ecco quindi nascere le specificheper la nuova generazione di microformati e per lintegrazione tra HTML5 e RDFa. Ma non ètutto, attorno a quello che può essere definito il nucleo autentico delle specifiche gravitano tutta unaserie di altre iniziative, alcune delle quali in avanzato stato di definizione, studiate per: accedere alle informazioni geografiche del device dellutente (posizione, orientamento,...); mantenere un database sul device dellutente; generare grafica 3D in tempo reale;E non dimentichiamo che levoluzione dellHTML viaggia di pari passo con quella dei CSS, che siavvicinano alla terza versione, e di altri importanti standard come SVG e MathML, e che ognuno diquesti componenti è progettato nella sua versione più recente per recare e ricevere beneficio daglialtri.Perché dovremmo passare allHTML5?Il panorama di Internet è cambiato molto dallassunzione a W3C Reccomandation della versioneprecedente delle specifiche, avvenuta verso la fine del 1999. In quel tempo il Web erastrettamente legato al concetto di ipertesto e lazione più comune per lutente era la fruizione dicontenuti, tipicamente in forma testuale. La mediamente bassa velocità di connessione e il limitatoinvestimento sul media contribuivano ad una scarsa presenza di applicazioni web, più care dasviluppare ed esigenti in termini di banda.Tutto questo era ben rappresentato da un linguaggio, HTML, principalmente orientato ad agevolarela stesura di semplici documenti testuali collegati fra loro. Negli anni successivi linteresseintorno alla rete ha subito una brusca accelerazione e questo ha condizionato positivamente sia ladiffusione che la velocità di connessione della stessa, attirando di conseguenza maggiori investimentie ricerca. Al modello di fruizione dei contenuti si è aggiunta la possibilità per lutente finale di divenireesso stesso creatore attraverso applicazioni web sempre più elaborate ed interessanti.Questo nuovo livello di complessità, in termini di sviluppo, ha però dovuto scontrarsi con un set dispecifiche poco inclini ad essere utilizzate per tali fini e che quindi si sono prestate al compito solo ascapito di infiniti hack e workaround. Esempi di questi utilizzi non premeditati dellHTML si possonotrovare un po ovunque, famoso il caso degli attributi rel e ref che hanno assunto nel tempo valorinon previsti, (eg:nofollow) anche esterni alla loro funzione naturale (eg: lutilizzo di questi dueattributi in librerie come Lightbox).
  • 6. Parallelamente il percorso di crescita del web ha fatto emergere alcune strutture di contenutoricorrenti, ben caratterizzate dal fenomeno dei blog: informazioni di testata, menu di navigazione,elenchi di articoli, testo a pie di pagina, ed altri. La parte dedicata al singolo articolo presentaanchessa solitamente lo stesso set di informazioni quali autore, data di pubblicazione, titolo e corpodel messaggio. Anche in questo caso lHTML4 non ha saputo fornire gli strumenti adatti a consentireuna corretta gestione e classificazione del contenuto obbligando gli sviluppatori web a ripiegare sustrutture anonime, quali <div> e<p>, arricchite di valore semantico con lutilizzo di attributi qualiclass e id.LHTML5 nasce per risolvere questi problemi offrendo agli sviluppatori web un linguaggio pronto adessere plasmato secondo le più recenti necessità, sia dal lato della strutturazione delcontenutoche da quello dello sviluppo di vere e proprie applicazioni.Grandi cambiamenti nellombraLa differenza principale tra le versioni correnti di HTML e XHTML risiede nella sintassi. Il linguaggio dimarkup creato da Tim Berners-Lee, e che ancora oggi popola i nostri browser, è stato studiato comeapplicazione del più generico SGML, Standard Generalized Markup Language; ne è la prova ladichiarazione di Document Definition Type che dovrebbe essere posta nella prima riga di una paginaWeb ad indicare la grammatica, HTML per lappunto, usata nel documento:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/ strict.dtd">In realtà la quasi totalità dei browser ignora la definizione e interpreta il documento secondo logichepiù permissive, frutto di anni di eccezioni e di esperienza accumulata su pagine malformate. LXHTML,invece, è una versione della sintassi HTML costretta allinterno delle regole XML, a sua voltagrammatica SGML: questo approccio dovrebbe implicare un maggior rigore nella pagina e laderenzaa regole quali lobbligo di chiusura di tutti i tag. Il parser XML inoltre dovrebbe sospenderelinterpretazione della pagina al primo errore rilevato.Larrivo dellHTML5 introduce una importante novità in questo scenario, per la prima volta lobiettivodelle specifiche è quello di definire un linguaggio ubiquo, che possa poi essere implementatosu entrambe le sintassi. Loccasione è buona anche per fare un po di pulizia e romperedefinitivamente il legame tra HTML e SGML formalizzando e traducendo in standard le regole adottateda tempo nei browser. Per indicare un documento HTML5 è nata quindi la seguente sempliceistruzione:<!DOCTYPE html>Che si affianca a quella da utilizzare in caso si intenda scrivere una pagina XHTML5:<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">E adesso?Questa lezione aveva lobiettivo di fornire un contesto storico e operativo ai temi dei quali questaguida tratterà in modo approfondito. Nelle prossime lezioni affronteremo in sequenza prima la parte
  • 7. legata al markup ed alla gestione della disposizione del contenuto e successivamente le principali APIintrodotte da queste specifiche. Il viaggio allinterno delluniverso dellHTML5 è appena iniziato! La sintassi di HTML5Prima di scendere nei dettagli presentando i nuovi elementi e le nuove API definite nella specifica, ènecessario spendere qualche momento per parlare delle regole sintattiche introdotte dall’HTML5, perlarga misura ereditate e razionalizzate dalla precedente versione delle specifiche. In primo luogofamiliarizziamo con il concetto noto di tag. Esistono tre distinte versioni di questa particella, ognunadi esse si applica selettivamente solo ad alcuni elementi:Tag ‘classico’<p> bla bla bla bla ... </p>Tag ‘vuoto’<img src="immagine_interessante.jpg" alt="Una immagine interessante">Tag ‘autochiudente’<rect x="150" y="40" width="60" height="30" fill="black" stroke="black"/>Gli elementi HTML5 si possono dividere in tre categorie sulla base della tipologia di tag da usare perimplementarli.1. Elementi normali: sono quelli che possono racchiudere dei contenuti sotto forma di testo,commenti HTML, altri elementi HTML, etc. Sono elementi normali, dunque, i paragrafi (<p>), le liste(<ul>), i titoli (<h1>), etc. Salvo specifici casi, cui accenneremo nel seguito della lezione, gli elementinormali vengono definiti attraverso un tag di apertura (<p>) e un tag di chiusura (</p>).2. Elementi vuoti: gli elementi vuoti sono quelli che non possono avere alcun contenuto. Per questielementi si utilizza un tag ‘vuoto’. Essi sono: area, base, br, col, command, embed, hr, img, input,keygen,link, meta, param, source, track, wbr.Per gli elementi vuoti, la chiusura del tag, obbligatoria in XHTML, è invece opzionale. Possiamodunque definire un tag <img> secondo le regole XHTML:<img src="immagine.png" alt="testo" />O seguendo la vecchie regole di HTML 4:<img src="immagine.png" alt="testo">3. Elementi provenienti da altri namespace: per questi elementi sono richiesti i tag‘autochiudenti’. Si tratta degli elementi adottati da specifiche esterne, come SVG e MathML.Maiuscolo, minuscoloUna delle differenze principali rispetto alle regole XHTML riguarda luso del maiuscolo e del minuscoloper definire un tag. In XHTML è obbligatorio usare il minuscolo. In HTML5 è consentito scrivere un tagusando anche il maiuscolo:
  • 8. <IMG src="immagine.png" alt="testo">Casi particolariEsistono alcune casistiche per le quali un tag classico può mancare della sua particella di apertura o dichiusura; questo succede quando il browser è comunque in grado di determinare i limiti di operativitàdell’elemento. Gli esempi più eclatanti riguardano i tag ‘contenitori’, come head, body e html, chepossono essere omessi in toto a meno che non contengano un commento o del testo come istruzionesuccessiva. È quindi sintatticamente corretto scrivere un documento come segue:<meta charset="utf-8"><title>Pagina HTML5 Valida</title><p>Un paragrafo può non avere la particella di chiusura<ol> <li>e anche un elemento di lista</ol>Notiamo che, come mostrato nell’esempio, anche i tag p e li possono essere scritti omettendo laparticella di chiusura, a patto che l’elemento successivo sia all’interno di una cerchia di elementidefinita dalle specifiche. A fronte di queste opzioni di semplificazione è però errato pensare che lapagina generata dal codice di cui sopra manchi, ad esempio, dell’elemento html; esso è infattidichiarato implicitamente ed inserito a runtime dallo user-agent.Per un quadro dettagliato rimandiamo a questa sezione(http://www.w3.org/TR/html5/syntax.html#optional-tags) delle specifiche.AttributiAnche rispetto alle definizione degli attributi HTML5 consente una libertà maggiore rispetto a XHTML,segnando di fatto un ritorno alla filosofia di HTML 4. In sintesi: non è più obbligatorio racchiuderei valori degli attributi tra virgolette.I casi previsti nella specifica sono 4.Attributi vuoti: non è necessario definire un valore per lattributo, basta il nome, il valore si ricavaimplicitamente dalla stringa vuota. Un caso da manuale:Secondo le regole XHTML:<input checked="checked" />In HTML5:<input checked>Attributi senza virgolette: è perfettamente lecito in HTML5 definire un attributo senza racchiudereil valore tra virgolette. Esempio:<div class=testata>
  • 9. Attributi con apostrofo: il valore di un attributo può essere racchiuso tra due apostrofi (termine piùcorretto rispetto a virgoletta singola). Esempio:<div class=testata>Attributi con virgolette: per concludere, è possibile usare la sintassi che prevede luso dellevirgolette per racchiudere il valore di un attributo. Il codice:<div class="testata">SemplificazioniIn direzione della semplificazione vanno anche altre indicazioni. Ci soffermiamo su quelle riguardantidue elementi fondamentali come style e script. La sintassi tipica di XHTML prevede laspecificazione di attributi accessori come type:<style type="text/css"> regole CSS... </style><script type="text/javascript" src="script.js"> </script>In HTML5 possiamo farne a meno, scrivendo dunque:<style> regole CSS... </style><script src="script.js"> </script>ConclusioniCome abbiamo sperimentato, la sintassi HTML5 si caratterizza per una spiccata flessibilità esemplicità di implementazione. Le osservazioni che abbiamo snocciolato in questa lezione sonochiaramente valide a patto di implementare la serializzazione HTML; ricordiamo infatti che lespecifiche prevedono anche l’utilizzo di una sintassi XML attraverso l’uso delle istruzioni:<!doctype html><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">Infine, per una migliore leggibilità del codice sorgente, consigliamo di ricorrere il meno possibileall’utilizzo di elementi impliciti, scrivendo sempre tutti i tag necessari nella loro forma completa. Elementi disegnati per un web modernoAll’inizio erano tabelle; ricordiamo tutti bene il tedio provocato dal dover costruire strutture complesse
  • 10. spezzandole all’interno di una griglia fatta da infiniti <tr> e <td>: un attività noiosa, resa ancorapeggiore dalla scarsa qualità e flessibilità del risultato. Poi arrivarono i <div> e fu una vera e propriarivelazione; finalmente un modello di costruzione del documento pensato per separare in modo chiaroi contenuti tipici di una pagina web. Grazie alla commistione tra questo elemento e i CSS nacqueropagine con codici HTML eleganti e leggibili come:<html><head></head> <body> <div id="header"> --- Titolo e Testata --- </div> <div id="body"> <div id="menu"> --- Voci di Menu --- </div> <div id="main_content"> <div class="post"> --- Un Post --- </div> <div class="post"> --- Un altro Post --- </div> </div> </div> </body></html>All’interno di un costrutto come questo è tutto molto semplice da interpretare: basta seguire il flussodei rientri di pagina facendosi guidare dai valori semantici attribuiti a id e class.Passarono anni e il modello cominciò a mostrare le sue prime debolezze; in primo luogo ci si accorseche da un lato non vi era una regola collettiva e quello che per uno sviluppatore era ‘body’ per l’altropoteva benissimo essere ‘corpo’; inoltre si realizzò che né il browser né tantomeno i motori di ricercaavrebbero mai potuto beneficiare di questa divisione semantica, proprio per colpa di quell’arbitrarietàche permetteva a milioni di siti web di essere organizzati in strutture simili ma sempre leggermentediverse tra loro e per questo non raggruppabili secondo schemi automatici. Emerse in questo modouno dei più grandi problemi dell’HTML4: l’incapacità di descrivere il significato delleinformazioni di una pagina web in un formato interpretabile da altri software. In un mondosempre più caratterizzato dall’interconnessione e dall’aggregazione su base semantica dei contenuti cisi adattò inventando e condividendo convenzioni studiate per rappresentare eventi di calendario,persone e quant’altro; nacquero così diversi microformati, come ad esempio hRecipe(http://microformats.org/wiki/hrecipe) per le ricette:<span class="hrecipe"> <span class="fn">Tisana alla liquirizia</span> <span class="ingredient">2 cucchiai di Zucchero</span> <span class="ingredient">20g Radice di liquirizia</span> <span class="yield">2</span> <span class="instructions">
  • 11. Scaldare un pentolino con 200cl d’acqua fino a 95°C; versare la radice di liquirizia; lasciar macerare per 7 minuti; zuccherare e servire. </span> <span class="duration"> <span class="value-title" title="PT90M"></span> 90 min </span></span>L’HTML5 nasce per gestire ed incanalare tutte queste problematiche; nelle prossime lezioniscopriremo come beneficiare di nuovi tag disegnati appositamente per le più comuni strutture dicontenuto e di attributi utilizzabili per definire ulteriore contenuto semantico alle pagine. Ma perarrivare a questo prima serve fare un po’ di pulizia...Elementi e attributi non più previsti nelle specificheLe specifiche HTML5 (http://dev.w3.org/html5/spec/Overview.html) sanciscono definitivamente lafine di tutta una serie di elementi e attributi che mantengono validità formale solo perpreservare la retrocompatibilità di pagine datate ma sono espressamente vietati nella creazione dinuovi documenti.I primi a subire questo esilio sono tutti quei costrutti funzionali alla parte di presentazione e cadutiampiamente in disuso con l’introduzione dei fogli di stile. Stiamo parlando di elementi come:basefont, big,center, font, s, strike, tt e u.Ad essi si aggiunge una moltitudine di attributi più o meno noti, tra i quali ricordiamo: align evalign, background, bgcolor, cellpadding, border, cellspacing e molti altri. In realtà alcuni tra icitati perdurano solamente su specifici elementi, per una lista completa ed esaustiva consigliamo divisionare questa pagina del W3C (http://www.w3.org/TR/html5-diff/#absent-attributes) dedicata altema.Interessante notare come si sia deciso invece di mantenere elementi come i e b; trasformandoli,però, da modificatori tipografici a semplici indicatori di porzioni di testo particolari econsentendone l’uso solo come ultima risorsa.La falce della semplificazione si è successivamente abbattuta su un piccolo elenco di elementiobsoleti: acronym (sostituibile dal più comune abbr), applet (rimpiazzato da object), isindex (giàarcaico in HTML4) e infine dir, sfavorito nel confronto con ul.Cadono, infine, anche tutti i tag che gravitano intorno al concetto dei frame, ritenuti dannosi perusabilità e accessibilità: frame, frameset e noframes.E con questi ultimi si chiude la lista degli elementi soppressi; in loro onore terminiamo la lezione conun piccolo snippet che li omaggi:<center> <font color="blue" size="2"> <big>Addio</big>, <s>monti sorgenti dallacque, ed elevati al cielo; cime</s> elementi di markup inuguali, noti a chi è cresciuto tra voi,
  • 12. e impressi nella sua mente, non meno che lo sia laspetto de suoi più familiari. </font> Liberamente adattato da: <acronym title="I Promessi Sposi">IPS</acronym></center> Attributi globaliDi attributi globali (quelli cioè che si possono applicare a tutti gli elementi HTML) ce ne sonosempre stati: basti pensare al classico ‘id’, disponibile da sempre sulla totalità degli elementi.HTML5 formalizza questa definizione e arricchisce lo sparuto gruppo con nuovi membri che, comeintuibile, possono essere applicati a un qualsiasi tag di queste specifiche. In questo capitolodedicheremo qualche paragrafo ad ognuno dei nuovi arrivati, alcuni dei quali, vedrete, sonodecisamente interessanti.Modificare il contenuto di una pagina: contenteditableTinyMCE, CKEditor e WYMeditor sono solo tre di una lunga lista di librerie studiate per offrire unostrumento di editing testuale su web che superi le classiche textarea. I risultati sono già ad oggieccellenti, vicini a prodotti desktop come Microsoft Word, ma le soluzioni implementate fanno tutteuso di escamotage più o meno furbi per ottenere questo livello di interazione in quanto l’HTML 4 nonprevede alcun modo esplicito di generare controlli del genere.Durante la stesura delle specifiche HTML5 questo problema è stato affrontato e si è deciso disviluppare un approccio comune al rich-editing di un documento re-introducendo un set di specificheimplementate in sordina da Microsoft (http://msdn.microsoft.com/en-us/library/ms537837(VS.85).aspx) nella versione 5.5 di Internet Explorer. Questo lavoro ha portatoalla creazione di un nuovo attributo globale:contenteditable, che impostato a true su di un qualsiasielemento lo rende modificabile da browser; lo stesso destino subiscono tutti gli elementi in essocontenuti a meno che non espongano un esplicitocontenteditable=false.Ma... cosa significa esattamente modificabile da browser? Che tipo di feedback visivo ci sidovrebbe aspettare? E come si comporterebbe il markup a fronte delle modifiche? Sfortunatamentequi le specifiche non sono troppo chiare e sanciscono semplicemente che qualsiasi cosa vengaconcessa all’utente il risultato deve comunque restare conforme all’HTML5: questa libertà operativaha prodotto comportamenti diversi da browser a browser; ad esempio c’è chi traduce il tasto inviocom un <br> e chi invece crea un nuovo paragrafo con <p>. Parallelamente è disponibile anche un setdi API utilissime (http://dev.w3.org/html5/spec/dnd.html%23execCommand) per insistere sulla zonamodificabile con comandi attivati dall’esterno, come ad esempio da una toolbar. Un pulsante chevolesse attivare/disattivare il grassetto sulla selezione corrente dovrebbe invocare la seguentefunzione:document.execCommand(bold)Prima di passare oltre sappiate che l’attributo contenteditable è stato applicato con valore true aall’intera sezione precedente con l’esclusione di questo paragrafo, permettendovi così di editarla esperimentare l’interazione di questa nuova interessante caratteristica! (e se selezionate del testo ecliccate qui (javascript:document.execCommand(bold);), potrete renderlo grassetto!).
  • 13. Menu contestuali associati ad un elemento:contextmenuL’attributo globale contextmenu serve ad associare a un elemento un menu contestuale;questa forma di interazione è poco comune sul web ma molto praticata sul desktop dove, ad esempio,su di una cartella di sistema ci si aspetta di poter operare azioni quali ‘copia’, ‘elimina’ e ‘rinomina’.Vediamo un esempio:<img src="http://farm4.static.flickr.com/3623/3527155504_6a47fb4988_d.jpg"contextmenu="image_menu"><menu type="context" id="image_menu"> <command label="Modifica il contrasto" onclick="contrastDialog();"> <command label="Negativo" onclick="negativo();"></menu>Cliccando con il tasto destro del mouse sull’immagine il browser dovrebbe mostrare un menucontenente le due azioni disponibili. Purtroppo ad oggi non esiste ancora nessuna implementazionefunzionante di questa feature, che resta al momento relegata a semplice specifica.Lʼattributo data-*L’HTML5 predispone la possibilità di associare ad ogni elemento che compone la pagina un numeroarbitrario di attributi il cui nome può essere definito dall’utente sulla base di esigenze personali, apatto che venga mantenuto il suffisso ‘data-’; ad esempio:<img id="ombra" class="cane" data-cane-razza="mastino corso” data-cane-eta="5" data-cane-colore="nero" src="la_foto_del_mio_cane.jpg">È inoltre interessante notare come queste informazioni, che arricchiscono e danno valore semanticoall’elemento, siano accessibili anche attraverso un comodo metodo Javascript:alert("Ombra ha :" + document.getElementById("ombra").dataset.caneEta + " anni");La fine del display:none in linea: hiddenL’attributo globale hidden è stato introdotto per offrire un’alternativa all’utilizzo del predicato‘style="display:none"’ che ha subito una proliferazione incontrollata soprattutto a seguito delladiffusione di librerie Javascript come jQuery o Prototype. Un elemento marcato come hidden deveessere considerato dallo user agent come non rilevante e quindi non visualizzato a schermo.SpellcheckLa quasi totalità dei browser oggi in commercio contiene un motore di verifica della sintassigrammaticale. Le specifiche HTML5 introducono un meccanismo per abilitare o disabilitare ilcontrollo della sintassi su porzioni della pagina modificabili dall’utente. L’attributo in questione si
  • 14. chiama spellcheck e, quando impostato a true, ordina al browser di attivare il proprio correttoresull’elemento corrente e su tutti i suoi figli.Laddove invece non venga impostata nessuna preferenza, le specifiche prevedono che il browserutilizzi un proprio comportamento di default.Altri attributi globaliCi sono un paio di altri attributi globali introdotti dalle specifiche e non trattati in questa sede,draggable e aria-*; entrambi sottendono un discorso che si estende ben al di là della sempliceimplementazione di markup e verranno trattati più avanti nella guida.Ecco comunque la lista di tutti gli attributi globali previsti dalla specifica:accesskey, class, contenteditable, contextmenu, dir, draggablehidden, id, lang, spellcheck, style, tabindex, titleTabella del supporto sui browserAttributi globalicontenteditable 5.5+ 3.0+ 3.1+ 2.0+ 9.0+contextmenu No No No No Nodata-* No No 5.0+ 6.0+ Nodraggable No 3.5+ 5.0+ 5.0+ Nohidden No 4.0+ Nightly build Nightly build Nightly buildspellcheck No 2.0+ No No NoConclusioniIn questa lezione abbiamo appreso che la nuova configurazione di markup dell’HTML5 è stata studiataper ovviare a tutti i problemi emersi in anni sviluppo di siti web e applicazioni con la precedenteversione delle specifiche. Nelle prossime lezione introdurremo il nuovo content model, pensato nonpiù nella forma binaria ‘block’ e ‘inline’ ma articolato in una serie di modelli di comportamentocomplessi ed interessanti. Un nuovo content modelNon più solo divEcco come si potrebbe codificare l’esempio della lezione precedente utilizzando i nuovi elementi messia disposizione dall’HTML5:<!doctype html><html lang="it"><head></head> <body>
  • 15. <header> --- Titolo e Testata --- </header> <nav> --- Voci di Menu --- </nav> <article> --- Un Post --- </article> <article> --- Un altro Post --- </article></body></html>Come si può notare, i tag introdotti hanno un nome in strettissima attinenza con il propriocontenuto; questo approccio risolve in modo elegante sia il problema dell’utilizzo dell’attributo classcon valore semantico, sia la riconoscibilità delle singole aree del documento da parte di un browser.Ma non è tutto; l’introduzione di article, nav, header e altri tag che vedremo, impone anchesostanziose novità al modo in cui lo user-agent deve comportarsi nell’interpretare questi elementi.Contenuti in una bolla di saponePartiamo dal seguente esempio HTML4:<html><body> <h1>I diari di viaggio:</h1> <h2>A spasso per il mondo alla scoperta di nuove culture:</h2> <h3>Giro turistico della Bretagna</h3> <p>lorem ipsum..</p> <h3>Alla scoperta del Kenya</h3> <p>lorem ipsum..</p> <h3>Cracovia e la Polonia misteriosa</h3> <p>lorem ipsum..</p> <p>tutti i viaggi sono completi di informazioni su alberghi e prezzi</p></body></html>Se lo visualizziamo avremo un risultato assolutamente strutturato come questo:Figura 3 (click per ingrandire) - Struttura del documento
  • 16. (http://www.html.it/guide/esempi/html5/imgs/lezione_5/immagine_1.png)Supponiamo ora di voler dividere i viaggi per continente. Con il modello attuale saremmo obbligati acambiare l’elemento h3 in h4 in modo da fare spazio alla nuova suddivisione:<html><body> <h1>I diari di viaggio:</h1> <h2>A spasso per il mondo alla scoperta di nuove culture:</h2> <h3>Europa</h3> <h4>Giro turistico della Bretagna</h4> <p>lorem ipsum..</p> <h4>Cracovia e la Polonia misteriosa</h4> <p>lorem ipsum..</p> <h3>Africa</h3> <h4>Alla scoperta del Kenya</h4> <p>lorem ipsum..</p> <p>tutti i viaggi sono completi di informazioni su alberghi e prezzi</p></body></html>Questo accade perché la gerarchia delle intestazioni è assoluta rispetto all’intero documento e ognitag <h*> è tenuto a rispettarla. Nella maggior parte dei casi però questo comportamento è fastidiosoin quanto è molto comune avere a che fare con contenuti che, come articoli o commenti, vorremmoavessero una struttura indipendente dalla loro posizione nella pagina. In HTML5 questo è stato resopossibile definendo una nuova tipologia di content model, chiamato ‘sectioning content’, al qualeappartengono elementi come article e section. All’interno di tag come quelli appena citati la vitascorre come in una bolla di sapone, quindi l’utilizzo di un <h1> è considerato relativo alla sezione incui si trova.
  • 17. Riprendiamo l’esempio precedente ed interpretiamolo in salsa HTML5:<!doctype html><html><head> <title>I diari di viaggio</title></head><body> <header> <hgroup> <h1>I diari di viaggio:</h1> <h2>A spasso per il mondo alla scoperta di nuove culture:</h2> </hgroup> </header> <section> <h1>Europa</h1> <article> <h1>Giro turistico della Bretagna</h1> <p>lorem ipsum..</p> </article> <article> <h1>Cracovia e la Polonia misteriosa</h1> <p>lorem ipsum..</p> </article> </section> <section> <h1>Africa</h1> <article> <h1>Alla scoperta del Kenya</h1> <p>lorem ipsum..</p> </article> </section> <p>tutti i viaggi sono completi di informazioni su alberghi e prezzi</p></body></html>Molto meglio! Ora i singoli componenti di questo documento sono atomici e possono essere spostatiall’interno della pagina senza dover cambiare la loro struttura interna. Inoltre, grazie a questedivisioni, il browser riesce a discernere perfettamente il fatto che l’ultimo paragrafo non appartenga altesto del viaggio in Kenia.Diamo prova dell’atomicità creando un blocco dedicato all’ultimo articolo inserito: ‘Un week-end aBarcellona’:<!doctype html><html><head> <title>I diari di viaggio</title></head><body>
  • 18. <header> <hgroup> <h1>I diari di viaggio:</h1> <h2>A spasso per il mondo alla scoperta di nuove culture:</h2> </hgroup> </header> <article> <h1>Un week-end a Barcellona</h1> <p>lorem ipsum..</p> </article><!-- resto della pagina -->Anche grazie a questo content model l’HTML5 introduce un nuovo e preciso algoritmo per il calcolodell’outline del documento. La vista ad outline, tipica nei software di word processing e ancora nonpresente nei browser, è utilissima nella navigazione dei contenuti di una pagina. Sperimentiamoquesta feature installando un’apposita estensione per Chromium(https://chrome.google.com/extensions/detail/afoibpobokebhgfnknfndkgemglggomo):Figura 4 (click per ingrandire) - Vista ad outline del documento(http://www.html.it/guide/esempi/html5/imgs/lezione_5/immagine_2.png)È interessante notare come l’algoritmo non solo identifichi correttamente i vari livelli di profondità, maper ognuno di essi sappia anche recuperare il titolo adeguato. Nell’HTML5 è vitale che il design dellapagina si rispecchi in una outline ordinata e coerente, questa infatti è la miglior cartina tornasolepossibile in merito al corretto utilizzo delle specifiche: ad esempio, in una prima revisione dellalezione, il codice HTML precedente mancava dell’elemento hgroup, utile a raggruppare elementi checoncorrono a formare un titolo. L’errore è stato individuato e corretto proprio grazie allavisualizzazione di una outline errata:Figura 5 (click per ingrandire) - Strutturazione corretta del documento
  • 19. (http://www.html.it/guide/esempi/html5/imgs/lezione_5/immagine_3.png)Concludiamo la trattazione di questo content model citando la presenza di alcuni elementi che, purseguendo le linee interpretative del sectioning content, devono essere ignorati dallalgoritmo dioutline. Tali tag sono definiti sectioning roots ed il motivo della loro esclusione è legato al fatto cheessi non concorrono tanto alla struttura dei contenuti della pagina quanto allarricchimento dellastessa. Fanno parte di questo elenco elementi come: blockquote, details, fieldset, figure e td.Seppur esclusi dalloutline del documento, nulla vieta agli appartenenti di questo gruppo di avere unapropria outline interna. Panoramica sui content model e presentazione del primo progetto guidaLo scopo di questa lezione è duplice: da un lato riallacciarsi al tema del sectioning content per offrireuna visione di ampio respiro in merito alle differenti tipologie di disposizione di contenuto offertedallHTML5, dallaltro iniziare la stesura del primo progetto guida.Una panoramica completaEsistono altri content model oltre a quelli trattati nella lezione precedente, alcuni implicitamentepresenti anche nelle vecchie specifiche, altri nuovi di zecca, per una rappresentazione grafica rimandoallottima infografica (http://www.whatwg.org/specs/web-apps/current-work/multipage/content-models.html#kinds-of-content) dello stesso W3C, fra laltro realizzata usando la sintassi SVG (provatea scorrere il mouse sopra le varie aree dellinsieme).Metadata contentFanno parte di questa categoria tutti gli elementi utili alla definizione del documento nel suoinsieme: a livello di presentazione o di funzionamento.Tag: base, command, link, meta, noscript, script, style, title.
  • 20. Sectioning contentNe abbiamo appena parlato: il gruppo contiene tutti quegli elementi studiati per ospitarecontenuti atomici e semanticamente ordinati. È importante utilizzare almeno un appartenentealla categoria heading content all’interno di ognuno di questi tag, questo anche per non avere unoutline popolato da voci senza titolo (vedi immagine).Tag: article, aside, nav, section.Figura 6 (click per ingrandire) - Visualizzazione della struttura del documento(http://www.html.it/guide/esempi/html5/imgs/lezione_6/immagine_4.png)Heading contentTutti gli appartenenti a questo gruppo servono per definire titoli. Interessante notare come se lapresenza di uno di questi elementi non sia associata ad un sectioning content questo venga definitoimplicitamente.Tag: h1, h2, h3, h4, h5, h6, hgroupPhrasing contentIncorpora il testo del documento così come tutti i modificatori tipografici e visuali dello stesso.Tag: a (solo se contiene phrasing content a sua volta), abbr, area (se figlio di un elemento map),audio, b, bdi, bdo, br, button, canvas, cite, code, command, datalist, del (solo se contienephrasing content a sua volta), dfn, em, embed, i, iframe, img, input, ins (solo se contiene phrasingcontent a sua volta), kbd, keygen, label, map (solo se contiene phrasing content a sua volta), mark,math, meter,noscript, object, output, progress, q, ruby, s, samp, script, select, small, span,strong, sub, sup, svg, textarea, time, var, video, wbr.Embedded contentNe fanno parte tutti quegli elementi che, come il nome del gruppo suggerisce, incorporano nellapagina oggetti esterni.Tag: audio, canvas, embed, iframe, img, math, object, svg, video.Interactive contentQuesta categoria comprende tutto ciò specificatamente studiato per interagire con l’utente.
  • 21. Tag: a, audio (con l’attributo controls presente), button, details, embed, iframe, img (conl’attributo usemap presente), input (con l’attributo type diverso da hidden), keygen, label, menu(con l’attributotype="toolbar"), object (con l’attributo usemap presente), select, textarea, video(i con l’attributo controls presente).Come avrete notato ogni elemento può appartenere ad uno o più content models, anche a secondadella sua configurazione degli attributi. Oltre ai gruppi citati, che sono i principali, va ricordato flow,che raggruppa la quasi totalità degli elementi e alcuni gruppi creati specificatamente per i controlli deiform, che vedremo più avanti.Progetto guida - nel tag HEADCogliamo l’occasione di questa panoramica alla struttura dell’HTML5 per gettare le prime fondamentadel progetto guida: in questo capitolo vedremo come impostare e strutturare il contenitore dellapagina ed il tag head. Creiamo un file index.html ed iniziamo ad inserire i primi elementi:<!doctype html><html lang="it"><head> <title>We5! Il blog della guida HTML5</title></head></html>Fin qui, eccezion fatta per il doctype, nessuna differenza rispetto alla versione 4 delle specifiche;andiamo avanti aggiungendo alcuni tag meta e link:...<head> <title>We5! Il blog della guida HTML5</title> <link rel="stylesheet" href="monitor.css" media="screen"> <link rel="stylesheet" href="printer.css" media="print"> <link rel="stylesheet" href="phone_landscape.css" media="screen and (max-device-width: 480px) and (orientation: landscape)"> <link rel="stylesheet" href="phone_portrait.css" media="screen and (max-device-width: 480px) and (orientation: portrait)"></head>...Incuriositi dalla strana sintassi degli attributi media degli ultimi due <link>? State osservando unatipica media query: il CSS viene interpretato solamente se le condizioni dell’espressione sono valutatecome vere dallo user agent. Le media query, profetizzate già nel 1999, consentono di identificare ilcorretto CSS per un dato device con un incredibile livello di dettaglio, alcuni esempi:<!-- TV con scan dell’immagine progressiva --><link rel="stylesheet" href="progressive.css" media="tv and (scan: progressive)"><!-- Stampanti con almeno 1000dpi ---><link rel="stylesheet" href="printer.css" media="print and (min-resolution: 1000dpi)"><!-- Retina display --><link rel="stylesheet" href="retina.css" media="screen and (-webkit-min-device-pixel-
  • 22. ratio: 2)"><!-- Device monocromatici (Kindle, etc..) --><link rel="stylesheet" href="mono.css" media="screen and (monochrome)">Bene, completiamo questo capitolo aggiungendo icone e charset:<head> <meta charset="utf-8"> <!-- ..gli altri tag.. --> <link rel="icon" href="standard.gif" sizes="16x16" type="image/gif"> <link rel="icon" href="iphone.png" sizes="57x57" type="image/png"> <link rel="icon" href="vector.svg" sizes="any" type="image/svg+xml"></head>Come potete notare è ora possibile specificare un attributo sizes per ogni icona, in questo modo louser agent può liberamente scegliere quale icona abbia le dimensioni più adatte. Ci sono due motiviche giustificano l’inserimento della direttiva ‘charset’ in questo progetto: in primo luogo la nuovasintassi è molto più succinta della passata, seppur ancora valida:<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">In seconda istanza è intenzione dell’autore sottolineare come sussistano reali rischi di sicurezza legatiall’assenza di questa direttiva.Dalla prossima lezione analizzeremo nel dettaglio i singoli elementi che concorrono alla costituzionedella nuova impalcatura semantica del linguaggio. HeaderFunzioni e dati tecniciIl tag header serve a rappresentare "un gruppo di ausili introduttivi o di navigazione". Taledefinizione, seppure apparentemente vaga, contiene in sé i concetti chiave per comprendere appienola funzione di questo tag: 1. Lelemento <header> è un contenitore per altri elementi. 2. Lelemento <header> non va confuso con quella che è la testata/intestazione principale di un documento (quella che oggi si definisce in genere con il tag <h1>). 3. La natura e gli scopi dellelemento <header> non dipendono dalla sua posizione nel documento, ma dai suoi contenuti (ausili alla navigazione o elementi introduttivi). 4. Il suo uso non è obbligatorio e in alcuni casi può risultare superfluo se non utilizzato in maniera appropriata.<header> <h1>Questo è un titolo</h1> <h2>Questo è un sotto-titolo</h2> [...]
  • 23. </header>Header: esempi concretiRiprendendo il nostro progetto guida, dove nella lezione precedente(http://xhtml.html.it/guide/lezione/4966/panoramica-sui-content-model-e-presentazione-del-primo-progetto-guida/) abbiamo definito il contenuto dell<head>:<head> <meta charset="utf-8"> <title> We5! Il blog della guida HTML5 </title> <link rel="stylesheet" href="monitor.css" media="screen"> <link rel="stylesheet" href="printer.css" media="print"> <link rel="stylesheet" href="phone_landscape.css" media="screen and (max-device-width: 480px) and (orientation: landscape)"> <link rel="stylesheet" href="phone_portrait.css" media="screen and (max-device-width: 480px) and (orientation: portrait)"> <link rel="icon" href="standard.gif" sizes="16x16" type="image/gif"> <link rel="apple-touch-icon" href="iphone.png" sizes="57x57" type="image/png"> <link rel="icon" href="vector.svg" sizes="any" type="image/svg+xml"></head>A questo punto possiamo iniziare a comporre il <body> del nostro documento partendo proprio con iltag <header>, che con lelemento <hgroup> (http://xhtml.html.it/guide/lezione/4973/hgroup/)definisce il titolo principale del documento (del sito) e la cosiddetta tagline:<header> <hgroup> <h1>We5! Il blog della guida HTML5</h1> <h2>Approfittiamo fin da oggi dei vantaggi delle specifiche HTML5!</h2> </hgroup></header>Ma header non deve contenere necessariamente solo titoli <hn]]>! Se titolo e sottotitolo principalisono certamente elementi introduttivi ai contenuti successivi, è naturalmente un ausilio dinavigazione una lista di link che andrà a formare la barra di navigazione principale del sito. Ecco comepossiamo completare la struttura del nostro primo <header>:<header> <hgroup> <h1>We5! Il blog della guida HTML5</h1> <h2>Approfittiamo fin da oggi dei vantaggi delle specifiche HTML5!</h2> </hgroup> <nav>
  • 24. <h1>Navigazione:</h1> <ul> <li><a href="/home">Home</a></li> <li><a href="/about">Gli autori</a></li> <li><a href="/refactoring">Il progetto four2five</a></li> <li><a href="/archives">Archivio</a></li> </ul> </nav></header>Nel seguente schema abbiamo realizzato graficamente ciò che il codice semanticamente rappresentanel nostro progetto:Figura 8 - Struttura del documento: primo headerAbbiamo inserito una sezione di navigazione (http://xhtml.html.it/guide/lezione/4971/nav/) (<nav></nav>) introdotta da un elemento <h1> e strutturata con una lista non ordinata.In realtà, il menu di navigazione non deve essere necessariamente inserito nell<header>, nel nostroesempio non poteva essere fatto altrimenti ma esistono numerosi tipi di layout in cui il menu dinavigazione può essere facilmente slegato dagli elementi introduttivi di intestazione del documento.Il template del nostro progetto guida, lo accennavamo nelle precedenti lezioni, è relativo ad un blog.Nel corpo del documento, ad un certo punto, trova posto una sezione che ospita i contenuti principalidella pagina, i post. Per definire semanticamente la sezione useremo il tag <section>(http://xhtml.html.it/guide_preview/lezione/4969/section/); ciascun post sarà definito a livellostrutturale da un tag <article>(http://xhtml.html.it/guide_preview/lezione/4970/article/):
  • 25. <section> <h1>Lultimo post</h1> <article> [...] </article></section>Si noti, innanzitutto, come il tag <h1> che fa da titolo principale alla sezione non sia racchiuso in unelemento <header>. Ribadiamo: non è obbligatorio inserire i titoli <hn]]> allinterno di uncontenitore<header>.A questo punto, dobbiamo definire due elementi fondamentali per la struttura di un post di blog: iltitolo e la data. Sono certamente ausili introduttivi, secondo la definizione da cui siamo partiti. é piùche legittimo e sensato, pertanto, racchiuderli in un tag <header>:<section> <h1>Lultimo post</h1> <article> <header> <time datetime="2010-11-22" pubdate>Lunedì 22 Novembre</time> <h2>Nuove scoperte sul tag video!</h2> </header> <p> [...] </p> </footer> [...] </footer> </article></section>Ecco quindi come il nostro articolo potrebbe essere rappresentato graficamente:Figura 9 - Struttura del documento: header degli articoli
  • 26. I due scenari mostrati rendono bene lidea rispetto agli utilizzi tipici dellelemento <header>. Laspecifica suggerisce come altri contesti duso la tavola dei contenuti di una sezione, un form di ricercao i loghi più rilevanti presenti nel documento.Nella prossima lezione capiremo come utilizzare lelemento <footer> e quale è la sua rilevanzasemantica allinterno di un template.Tabella del supporto sui browserNuovi tag semantici e strutturali<header> 9.0+ 3.0+ 3.1+ 5.0+ 10.0+ FooterFunzioni e dati tecniciLelemento <footer> deve contenere in genere informazioni sulla sezione che lo contiene come: i dati di chi ha scritto i contenuti; collegamenti ai documenti correlati; i dati di copyright; e così via...Riguardo il suo apporto semantico ad una pagina web sembra essere tutto chiaro, ma più complessoè il suo utilizzo a livello pratico:
  • 27. Non necessariamente deve essere inserito solo alla fine di un documento. Quando contiene intere sezioni, esse rappresentano: appendici, indici, note, accordi di licenza e altri contenuti del genere. Non introduce una nuova sezione e quindi non è rilevante per loutliner (http://it.wikipedia.org/wiki/Outliner). Allinterno di una pagina web possono essere presenti diversi <footer> anche più di uno per lo stesso elemento.<footer> <small>©2011 Autore contenuto. Design by Designer sito </small></footer>Footer: esempi concretiRiprendendo il nostro progetto guida, dopo aver definito definito il contenuto dell<header>(http://xhtml.html.it/guide/lezione/4967/header/), possiamo vedere come il <footer> chiuda il blogdistaccandosi dalle altre sezioni in modo molto naturale, racchiudendo al proprio interno una lista cheaggiunge informazioni riguardo lautore della pagina e la data del suo ultimo aggiornamento; infine iltag <small>ridefinito nella specifica dellHTML 5 (http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-small-element) racchiude il copyright della pagina:<footer> <dl> <dt>Creato da</dt> <dd><address><a href="mailto:sandro.paganotti@gmail.com">Sandro Paganotti</a></address></dd> <dt>Ultimo aggiornamento</dt> <dd><time datetime="2010-11-23" pubdate>Marted&igrave; 23 Novembre</time></dd> <dd> </dl><small>Tutti i contenuti sono prottetti dalla licenza creative commons</small></footer>Nel seguente schema abbiamo realizzato graficamente ciò che il codice semanticamente rappresentanel nostro progetto (figura 1):Figura 10 - Struttura del documento: il footer principale
  • 28. schema template html5 [footer]Così come lintero documento, ogni articolo del nostro blog avrà un <footer> contenente il nomedellautore ed altre eventuali informazioni aggiuntive:<section> <h1>Lultimo post</h1> <article> <header> [...] </header> <p> [...] </p> <footer> <dl> <dt>autore:</dt> <dd><address><a href="mailto:sandro.paganotti@gmail.com">Sandro Paganotti</a></address></dd> <dt>categoria: </dt> <dd><a href="categoria/multimedia">multimedia</a>,</dd> <dt>tags: </dt> <dd><a href="tags/video">video</a>,</dd> <dd><a href="tags/canvas">canvas</a>,</dd> <dt>permalink: </dt> <dd><a href="2010/22/11/nuove-scoperte-sul-tag-video">permalink</a>,</dd> <dt>rank:</dt> <dd><meter value="3.0" min="0.0" max="5.0" optimum="5.0">ranked 3/5</meter></dd> </dl> </footer>
  • 29. </article></section>È da notare la scelta di inserire le informazioni riguardanti lautore dellarticolo allinterno del tag<dl>; infatti nella specifica HTML5 questo elemento viene ridefinito come contenitore di metadati equindi semanticamente corretto allinterno del nostro <footer>.Ecco quindi come il nostro articolo potrebbe essere rappresentato graficamente, tutte le informazionicontenute nel <footer> per comodità abbiamo deciso di chiamarle metadati:Figura 11 - Struttura del documento: footer degli articoliLelemento <footer> potrebbe essere inserito anche allinizio di un documento subito dopo il <body>oppure allapertura di un tag <article> (http://xhtml.html.it/guide_preview/lezione/4970/article/)ma in questi casi non dovrebbe contenere elementi introduttivi riguardo il contenuto della sezione chelo contiene; il suo uso in questa posizione potrebbe essere dovuto solamente a ragioni pratiche comead esempio la duplicazione del <footer> in fondo alla pagina quando i contenuti della stessa sonomolto lunghi:<body><footer> <a href="#indice">Torna allindice</a></footer><section> [Contenuti molto lunghi...]<section><section> [Contenuti molto lunghi...]<section><section>
  • 30. [Contenuti molto lunghi...]<section><footer> <a href="#indice">Torna allindice</a></footer></body>Nella prossima lezione parleremo del tag <section> e della sua importanza nel sezionare la pagina inblocchi semanticamente distinti.Tabella del supporto sui browserNuovi tag semantici e strutturali<footer> 9.0+ 3.0+ 3.1+ 5.0+ 10.0+ SectionFunzioni e dati tecniciIl tag <section>, secondo la definizione presente nella specifica HTML5, rappresenta una sezionegenerica di un documento o applicazione. Lelemento <section>, in questo contesto, individuaun raggruppamento tematico di contenuti,ed in genere contiene un titolo introduttivo.Vediamo quindi quali sono i punti fondamentali da ricordare riguardo il suo utilizzo: 1. lelemento <section> non deve essere utilizzato in sostituzione del <div> per impostare graficamente la pagina; inoltre è fortemente consigliato utilizzare i <div> anche quando risultano più convenienti per gli script; 2. lelemento <section> non deve essere preferito allelemento <article> quando i contenuti possono essere ripubblicati anche su altri siti; 3. lelemento <section> e lelemento <article> non sono indipendenti ed esclusivi: possiamo avere sia un <article> all interno di un <section> che viceversa.<article> <section> <h1>Titolo 1</h1> <p>Testo correlato al titolo 1.</p> </section> <section> <h1>Titolo 2</h1> <p>Testo correlato al titolo 2.</p> </section></article>Lelemento <section> può essere utilizzato in combinazione con lattributo cite attraverso il quale èpossibile specificare lurl dalla quale si stanno riportando i contenuti.
  • 31. Section: esempi concretiCome abbiamo visto nei capitoli precedenti, il codice del nostro progetto inizia a prendere una formapiù chiara e definita: infatti, dopo aver compreso lutilità semanticadell<header>(http://xhtml.html.it/guide_preview/lezione/4967/header/) e del <footer>(http://xhtml.html.it/guide_preview/lezione/4968/footer/), capiamo come utilizzare lelemento<section> allinterno del nostro blog.Per strutturare la pagina raggruppando i contenuti correlati, in ordine decrescente incontriamo leprime due grandi macrosezioni del blog: "lultimo post" e "i post meno recenti" contenuti quindi indue<section>:<section> <h1>Lultimo post</h1> <article> [contenuto del post...] <section> [commenti...] </section> </article></section><section> <h1>Post meno recenti</h1> <article> [contenuto del post...] </article> <article> [contenuto del post...] </article> <article> [contenuto del post...] </article></section>Nel seguente schema abbiamo realizzato graficamente ciò che il codice semanticamente rappresentanel nostro progetto:Figura 12 - Struttura del documento: sezioni principali
  • 32. Nel nostro progetto le <section>, oltre a poter raggruppare i vari <article>(http://xhtml.html.it/guide_preview/lezione/4970/article/), sono presenti anche allinterno del primo<article> per suddividere i commenti dal contenuto del post. La sezione dei commenti a sua voltacontiene unaltra sezione contenente il form per linserimento di un nuovo commento:<article> [contenuto del post...] <section> <article> [commento1...] </article> <article> [commento2...] </article> <article> [commento3...] </article> <section> [Inserisci un nuovo commento...] </section> </section> </section></article>In questo modo il post è diviso in maniera molto netta rispetto ai propri contenuti solo con lausilio deitag HTML5, separando quindi i commenti che sono una sezione aggiuntiva eventualmente ancheeliminabile dallargomento principale trattato allinterno dellarticolo.
  • 33. Lo schema dellarticolo analizzato è quindi il seguente:Figura 13 - Struttura del documento: suddivisione semantica del postIl tag <section> rappresenta un elemento che viene considerato una sezione a sé stante dalloutliner(http://it.wikipedia.org/wiki/Outliner) e quindi un blocco con dei contenuti univoci che necessitano diun titolo (<hN>) che li riassuma. Come vedremo nelle prossime lezioni esistono anche altri elementinelle specifiche HTML5 che sono considerati "contenitori di sezionamento dei contenuti"(http://xhtml.html.it/guide_preview/lezione/4965/un-nuovo-content-model/).Tabella del supporto sui browserNuovi tag semantici e strutturali<section> 9.0+ 3.0+ 3.1+ 5.0+ 10.0+ ArticleFunzioni e dati tecniciIl tag <article> rappresenta una sezione autonoma in un documento, pagina, applicazione osito; infatti è potenzialmente ridistribuibile o riutilizzabile, e quindi ripubblicabile in parte ointeramente in diverse pagine.
  • 34. Esso può identificare il post di un forum, un articolo di una rivista o di un giornale, larticolo di unblog, un commento, un widget interattivo, o qualsiasi cosa che abbia un contenuto indipendente.Prima di vedere un esempio concreto bisogna chiarire alcuni concetti riguardo il suo utilizzo: 1. quando gli elementi <article> sono nidificati, gli <article> interni rappresentano gli articoli che sono in linea di principio relativi al contenuto dell<article> esterno. Ad esempio, un blog che accetta commenti dagli utenti potrebbe rappresentarli come <article> figli annidati allinterno dellelemento padre <article>; 2. le informazioni relative allautore dell<article> non devono essere replicate allinterno degli elementi nidificati allinterno dello stesso; 3. lelemento <time> con lattributo pubdate può essere utilizzato per definire la data di pubblicazione dell<article>; 4. lelemento <section> e lelemento <article> non sono indipendenti ed esclusivi: possiamo avere sia un <article> all interno di un <section> che viceversa.<article> <header> <h1>Titolo articolo</h1> <time pubdate datetime="2011-10-09T14:28-08:00"></time></p> </header> <p>Contenuto dellarticolo</p> <footer> <p>Informazioni riguardo lautore</p> </footer></article>In sostanza, anche se nelle specifiche non è espresso, lelemento <article> rappresenta una formaparticolare di <section> (http://xhtml.html.it/guide_preview/lezione/4969/section/).Article: esempi concretiNella lezione precedente abbiamo diviso i contenuti centrali del blog che stiamo costruendo in due<section>. Allinterno della prima <section> possiamo trovare diversi tag <article>: il primo cheincontriamo è larticolo vero e proprio con tanto di <header>(http://xhtml.html.it/guide_preview/lezione/4967/header/) contenente il titolo dellarticolo e la datadi pubblicazione e <footer> che allinterno di un <dl> raccoglie i metadati riguardanti lautore.Allinterno dell<article> padre sono annidati ulteriori <article> contenenti i commenti allarticoloracchiusi in una <section> che li rende semanticamente separati dal contenuto principale. Così comei commenti, anche il form che permette di inserire unulteriore commento è inserito allinterno di una<section>. Possiamo quindi facilmente immaginare come il contenuto del nostro <article> possaessere citato o ripubblicato in altri blog indipendentemente dai commenti che ha ricevuto.Ecco quindi il codice dell<article> sopra descritto:<section> <h1>Lultimo post</h1><article> <header> <time datetime="2010-11-22" pubdate>Lunedì 22 Novembre</time> <h2>Nuove scoperte sul tag video!</h2> </header>
  • 35. <p> Attraverso un utilizzo sapiente del tag canvas è possibile leggere uno stream di dati proveniente da un tag video e <mark>manipolarlo in tempo reale</mark>. </p> <footer> <dl> <dt>autore: </dt> <dd><address><a href="mailto:sandro.paganotti@gmail.com">Sandro Paganotti</a></address></dd> <dt>categoria: </dt> <dd><a href="categoria/multimedia">multimedia</a>,</dd> <dt>tags: </dt> <dd><a href="tags/video">video</a>,</dd> <dd><a href="tags/canvas">canvas</a>,</dd> <dt>permalink: </dt> <dd><a href="2010/22/11/nuove-scoperte-sul-tag-video">permalink</a>,</dd> <dt>rank:</dt> <dd><meter value="3.0" min="0.0" max="5.0" optimum="5.0">ranked 3/5</meter></dd> </dl> </footer> <section> <h3>Commenti</h3> <article> <h4> <time datetime="2010-11-22" pubdate>Lunedì 22 Novembre</time> Angelo Imbelli ha scritto: </h4> <p>Cè un bellesempio sulla rete: effetto ambi-light!</p> <footer> <address><a href="mailto:ambelli@mbell.it">Angelo Imbelli</a></address> </footer> </article> <article> <h4> <time datetime="2010-11-23" pubdate>Martedì 23 Novembre</time> Sandro Paganotti ha scritto: </h4> <p>Bellissimo! Grazie per la segnalazione!</p> <footer> <address><a href="mailto:sandro.paganotti@gmail.com">Sandro Paganotti</a></address> </footer> </article> <section> <h4>Inserisci un nuovo commento:</h4> <form> [ campi form per inserire un nuovo commento] </form>
  • 36. </section> </section> </article></section>Nel seguente schema abbiamo realizzato graficamente come si presenta il nostro articolomorfologicamente:Figura 14 - Struttura del documento: suddivisione semantica degli articoliCè da notare che anche se il tag <article> rappresenta un elemento che viene considerato unasezione a sé stante dalloutliner (http://it.wikipedia.org/wiki/Outliner) e quindi un blocco con deicontenuti unici e un titolo univoco (quindi per ogni blocco avremmo potuto utilizzare un titoloracchiuso in un <h1>), abbiamo preferito rispettare comunque lordine decrescente per i titoli in mododa rendere i contenuti accessibili anche agli screen reader che al momento non hanno ancoraimplementato lalgoritmo outliner.Nella prossima lezione parleremo del tag <nav> e della sua fondamentale importanza allinterno diuna pagina in HTML5.Tabella del supporto sui browserNuovi tag semantici e strutturali
  • 37. <article> 9.0+ 3.0+ 3.1+ 5.0+ 10.0+ NavFunzioni e dati tecniciIl tag <nav> è uno degli elementi introdotti nelle specifiche HTML5 di più facile comprensione.Infatti, rappresenta una sezione di una pagina che contiene link (collegamenti) ad altre pagine oa parti interne dello stesso documento; quindi, in breve, una sezione contenente link dinavigazione.A questo punto potremmo potremmo porci una domanda: come mai un elemento così scontatamentefondamentale è stato introdotto solamente adesso? La risposta potrebbe essere che, così come per itag visti nelle precedenti lezioni, finalmente si è cercato di incentivare luso di standard condivisiproponendo elementi che possano aiutare gli sviluppatori proprio perché molto vicini ai modellimentali oramai assimilati dagli esperti e di semplice comprensione per i novizi del mestiere.Per poter utilizzare correttamente lelemento <nav> dobbiamo ricordare i seguenti punti: 1. solo sezioni che sono costituite da grandi blocchi di navigazione sono appropriati per lelemento <nav>; 2. i link a pie di pagina e le breadcumb non devono essere inseriti in una sezione <nav>; 3. lelemento <nav> non sostituisce i link inseriti in elementi come gli <ul> o gli <ol> ma deve racchiuderli.<nav> <ul> <li>Questo è un link</li> <li>Questo è un link</li> <li>Questo è un link</li> <li>Questo è un link</li> [...] </ul></nav>Nav: esempi concretiPrima di spiegare in che modo lelemento <nav> può essere inserito nel progetto che abbiamo presocome base, riassumiamo brevemente i tag spiegati nelle lezioni precedenti: Con lelemento <header> (http://xhtml.html.it/guide_preview/lezione/4967/header/) abbiamo indicato il titolo introduttivo del blog più i titoli dei singoli articoli. Con il <footer> (http://xhtml.html.it/guide_preview/lezione/4968/footer/) abbiamo racchiuso le informazioni relative agli autori dei contenuti, i metadati e il copyright. Con lelemento <section> (http://xhtml.html.it/guide_preview/lezione/4969/section/) abbiamo strutturato la parte centrale della pagina dividendola in due sezioni semanticamente distinte. Infine abbiamo utilizzato <article> (http://xhtml.html.it/guide_preview/lezione/4970/article/) per racchiudere i contenuti degli articoli.A questo punto non possiamo che inserire i link presenti nell<header> allinterno del tag <nav>:
  • 38. <header> <hgroup> <h1>We5! Il blog della guida HTML5</h1> <h2>Approfittiamo fin da oggi dei vantaggi delle specifiche HTML5!</h2> </hgroup> <nav> <h1>Navigazione:</h1> <ul> <li><a href="/home">Home</a></li> <li><a href="/about">Gli autori</a></li> <li><a href="/refactoring">Il progetto four2five</a></li> <li><a href="/archives">Archivio</a></li> </ul> </nav></header>Da notare la presenza del titolo <h1> che serve a specificare più dettagliatamente la funzione delnostro blocco di link e a conferirgli un titolo valido anche per loutliner. Il tag <nav>, infatti,rappresenta un elemento che viene considerato una sezione a sé stante dalloutliner(http://it.wikipedia.org/wiki/Outliner) e quindi un blocco con dei contenuti univoci che necessitano diun titolo che li riassuma.Nel seguente schema abbiamo realizzato graficamente ciò che il codice semanticamente rappresentanel nostro progetto:Figira 15 - Struttura del documento: visualizzazione grafica del tag navIn realtà (come già specificato nel paragrafo <header>) il menu di navigazione non deve esserenecessariamente inserito nel <header>, nel nostro esempio non poteva essere fatto altrimenti ma
  • 39. esistono numerosi tipi di layout in cui il menu di navigazione può essere facilmente slegato daglielementi introduttivi di intestazione del documento.Nel nostro esempio lelemento <nav> è presente anche nella colonna laterale del blog (<aside>) eracchiude un menu che ha come link le categorie nelle quali sono inseriti i vari articoli:<aside> <h1>Sidebar</h1> <section> <h2>Ricerca nel form:</h2> <form> [form di ricerca dei contenuti...] </form> </section> <nav> <h2>Categorie</h2> <ul> <li><a href="/categoria/multimedia">multimedia</a></li> <li><a href="/categoria/text">marcatori testuali</a></li> <li><a href="/categoria/form">forms</a></li> </ul> </nav></aside>Per comprendere quale è la funzione dellelemento <aside> che contiene il menu laterale non ci restaquindi che leggere la prossima lezione.Tabella del supporto sui browserNuovi tag semantici e strutturali<nav> 9.0+ 3.0+ 3.1+ 5.0+ 10.0+ AsideFunzioni e dati tecniciLelemento <aside> rappresenta una sezione di una pagina costituita da informazioni che sonomarginalmente correlate al contenuto dellelemento padre che la contiene, e che potrebberoessere considerate distinte da questultimo. Questo è ciò che viene indicato nelle specifiche HTML5,ma è facile immaginare lutilità del tag <aside> semplicemente pensandolo come un contenitore diapprofondimentoin cui possiamo inserire gruppi di link, pubblicità, bookmark e così via.<aside> <h1>Questi sono dei contenuti di approfondimento marginali rispetto al contenuto principale</h1> <nav> <h2>Link a pagine correlate al contenuto</h2> <ul>
  • 40. <li>Informazione correlata al contenuto</li> <li>Informazione correlata al contenuto</li> <li>Informazione correlata al contenuto</li> </ul> </nav> <section> <h2>Pubblicità</h2> [immagini pubblicitarie] <section></aside>Aside: esempi concretiRitornando al nostro progetto guida, dopo aver definito il contenuto dellelemento <nav>, possiamoanalizzare la parte di codice in cui abbiamo utilizzato il tag <aside>:<aside> <h1>Sidebar</h1> <section> <h2>Ricerca nel form:</h2> <form name="ricerca" method="post" action="/search"> <label> Parola chiave: <input type="search" autocomplete="on" placeholder="article, section, ..." name="keyword" required maxlength="50"> </label> <input type="submit" value="ricerca"> </form> </section> <nav> <h2>Categorie</h2> <ul> <li><a href="/categoria/multimedia">multimedia</a></li> <li><a href="/categoria/text">marcatori testuali</a></li> <li><a href="/categoria/form">forms</a></li> </ul> </nav></aside>Nel seguente schema abbiamo realizzato graficamente ciò che il codice semanticamente rappresentanel nostro progetto:Figura 16 - Struttura del documento: visualizzazione grafica del tag aside
  • 41. Come possiamo notare, il form per la ricerca di parole chiave e i link alle categorie presenti nel nostroblog non sono informazioni particolarmente rilevanti per il contenuto centrale della nostra pagina,pertanto possiamo facilmente separarli con lelemento <aside> che li qualifica come contenutimarginali.Nel nostro caso abbiamo utilizzato un <aside> per contenere la colonna sinistra del blog, ma inrealtà, visto che in diversi siti va di moda la presenza di footer molto grossi con diversi link,consigliamo di utilizzare lelemento <aside> in combinazione con il tag <nav> che potrebbe essere lasoluzione migliore per questa tipologia di contenuti dato che, come abbiamo potuto constatare nellalezione dedicata al footer, ciò non è possibile farlo allinterno del tag <footer>.Così come gli elementi <article> (http://xhtml.html.it/guide_preview/lezione/4970/article/),<section> (http://xhtml.html.it/guide_preview/lezione/4969/section/) e<nav>(http://xhtml.html.it/guide_preview/lezione/4971/nav/) anche l<aside> appartiene allacategoria dei "contenitori di sezionamento dei contenuti"(http://xhtml.html.it/guide_preview/lezione/4965/un-nuovo-content-model/) in quanto per loutlinernecessita di un titolo che riassuma i propri contenuti.Ricordiamo però che non è obbligatorio inserire un titolo per gli elementi che vengono consideratidelle sezioni a sé stanti dalloutliner, infatti in questo caso queste sezioni rimarrebbero senza titoloma non genererebbero nessun errore di validazione.Vediamo quindi ora che abbiamo completato la struttura del blog come è loutline del nostrodocumento Outline (esempi/outline_progetto/outline.html).Nella prossima lezione comprenderemo come usare lelemento <hgroup> e la sua importanza perloutline di un documento in HTML5.Tabella del supporto sui browser
  • 42. Nuovi tag semantici e strutturali<aside> 9.0+ 3.0+ 3.1+ 5.0+ 10.0+ HgroupFunzioni e dati tecniciLelemento <hgroup> rappresenta lintestazione di una sezione. Lelemento viene utilizzato perraggruppare un insieme di elementi h1-h6, quando il titolo ha più livelli, come sottotitoli, titolialternativi o slogan.<hgroup> <h1>Questo è il titolo</h1> <h2>Questo è un sottotitolo</h2></hgroup>La vera importanza del tag <hgroup> è che maschera loutline dellelemento padre che lo contiene;infatti, lalgoritmo delloutliner riconosce come un titolo solamente lheading con il valore più alto econsidera tutti gli altri elementi sottotitoli.Esempio:<article datetime="2010-11-22" pubdate > <header> <hgroup> <h2>Le prospettive per il futuro del web</h2> <h1>LHTML 5 rivoluzionerà il mondo del web</h1> </hgroup> </header> <p>Presto il web sarà pieno di siti e applicazioni che saranno in grado di mettere in crisi le più grandi case di desktop application...</p> <footer> <p>Pinco pallino</p> </footer></article>Se facessimo loutline della pagina HTML contenente questo <article>(http://xhtml.html.it/guide_preview/lezione/4970/article/) ci restituirebbe come titolo della sezionesolamente l<h1> contenuto nell<hgroup> (non considerando l<h2> anche se posto prima nelcodice) poiché è il tag con il valore più alto allinterno della sezione. Senza lelemento <hgroup> i duetitoli verrebbero considerati entrambi sullo stesso livello dimportanza come titoli dell <article>.Nella prossima lezione parleremo del tag <mark> e della sua utilità nellevidenziare partiparticolarmente importanti del testo.Tabella del supporto sui browser
  • 43. Nuovi tag semantici e strutturali<hgroup> 9.0+ 3.0+ 3.1+ 5.0+ 10.0+ MarkFunzioni e dati tecniciLelemento <mark> rappresenta una parte di un testo segnato o evidenziato allutente a causadella sua rilevanza anche in un altri contesti. Esso, in un testo in prosa, indica un punto culminanteche non era originariamente presente, ma che è stato aggiunto per attirare lattenzione del lettore suuna parte del testo che potrebbe non essere stata considerata rilevante dallautore originale quando ilcontenuto è stato scritto.Questa definizione abbastanza complessa in realtà può essere semplificata di molto chiarendoci leidee con un esempio: immaginiamo di cercare una determinata parola chiave in diverse pagine web eche la parola che abbiamo cercato nel motore di ricerca, ci venga evidenziata allinterno della paginache andiamo a visualizzare; ciò che abbiamo appena descritto è la situazione ideale per lutilizzo deltag <mark>poiché con questultimo dobbiamo racchiudere la parola ricercata segnalandolagraficamente allutente.<p>Senza <mark>plug in</mark> di terze parti il web potrebbe diventareper noi sviluppatori più democratico; con le nuove API HTML5 non abbiamo più bisognodi diversi <mark>plug in</mark> di terze parti che sino ad ora erano indispensabiliper i contenuti multimediali</p>Allo stato attuale non esiste un tag HTML standard utilizzato per evidenziare le parole chiave agliutenti che utilizzano i motori di ricerca per navigare: Google utilizza il tag <em>, Bing il tag <strong>,Yahoo il tag <b> e così via. Si spera che con lintroduzione dellelemento <mark> le cose possanocambiare.Nella prossima lezione parleremo del tag <time>, unaltra delle novità dellHTML5.Tabella del supporto sui browserNuovi tag semantici e strutturali<mark> 9.0+ 4.0+ 5.0+ 5.0+ 11.0+ Time e gli attributi pubdate e datetimeFunzioni e dati tecniciLelemento <time> rappresenta il tempo su un orologio di 24 ore, o una data precisa nelcalendario Gregoriano accompagnata opzionalmente con un orario e una differenza di fuso orario.Questo elemento è inteso come un modo moderno per codificare le date e gli orari in manieraleggibile anche per i computer. Ad esempio, i browser saranno in grado di offrire la possibilità di
  • 44. aggiungere promemoria per i compleanni o gli eventi in programma in una web application chefunziona da calendario.<p>Oggi pomeriggio penso che sarò lì per le <time>15:00</time></p>Prima di inserire lelemento <time> nelle nostre pagine in HTML5 dobbiamo comprendere quali sonoi contesti in cui è sconsigliato utilizzarlo: non bisogna inserire nel tag <time> le date che non possono essere determinate con precisione; ad esempio: "un giorno nel lontano inverno del 68","da quando è nato il primo uomo"...; non bisogna inserire nel tag <time> le date prima dellintroduzione del calendario Gregoriano.Lelemento <time> può possedere lattributo pubdate che è di tipo booleano; la sua presenza indicache la data presente nel tag <time> è anche la data nella quale è stato scrittol<article>(http://xhtml.html.it/guide_preview/lezione/4970/article/) padre più vicino, e nel casonon esistesse un <article> padre allora essa è riferita alla creazione dei contenuti dellinterodocumento.Ovviamente un elemento che possiede lattributo pubdate necessita di una data. Per ciascun<article> può esserci solo un singolo tag <time> con pubdate e la stessa cosa vale per linterodocumento.Possiamo specificare in maniera più dettagliata una data aggiungendo lattributo datetime: il valore dellattributo deve essere una "stringa valida" (http://www.whatwg.org/specs/web- apps/current-work/multipage/common-microsyntaxes.html#valid-global-date-and-time-string) del tipo (ANNO-MESE-GIORNO-ORE:MINUTI:SECONDI.MILLISECONDI-FUSO ORARIO). se lattributo datetime non è presente allora il contenuto testuale deltag <time> deve essere una "stringa valida" (http://www.whatwg.org/specs/web-apps/current- work/multipage/common-microsyntaxes.html#valid-global-date-and-time-string).<time pubdate datetime="2011-01-20">20 Gennaio</time>Dobbiamo specificare che lattributo pubdate in quanto di tipo booleano può essere inserito anche nelseguente modo:<time pubdate="pubdate" datetime="2011-01-20">20 Gennaio</time>Nella prossima lezione vedremo in quali occorrenze utilizzare il tag <meter>.Tabella del supporto sui browserNuovi tag semantici e strutturali<time> No No No No No MeterFunzioni e dati tecniciLelemento <meter> rappresenta una misura scalare allinterno di un intervallo noto, o unvalore frazionario.
  • 45. Il tag <meter> è anche utilizzato come un indicatore di livello.<meter value="6" max="8">6 blocchi utilizzati (su un totale di 8)</meter>Vediamo alcuni contesti in cui non deve essere utilizzato: quando indica lo stato di una barra di progresso; quando i valori rappresentati sono di tipo arbitrario a scalare; ad esempio non deve segnalare un peso o unaltezza a meno che non vi sia un valore massimo riconosciuto.Esistono 6 attributi per determinare il valore semantico dellelemento <meter>: 1. min: indica il valore limite minimo disponibile; 2. max: indica il valore limite massimo disponibile; 3. value: indica il valore dellelemento; 4. low: indica un valore che viene considerato basso; 5. high: indica un valore che viene considerato alto; 6. optimum: indica un valore che viene considerato "ottimale"; se è più alto del valore specificato nellattributo high indica che il valore più alto è il migliore,viceversa è più basso del valore specificato nellattributo low indica che il valore più basso è il migliore.Se non è specificato un valore minimo e un valore massimo questi sono di default rispettivamente 0 e1.Ad oggi lunico browser che renderizza il tag <meter> è Google Chrome presentandolo graficamentecome una barra di progresso, quindi gli sviluppatori sono fortemente incoraggiati a specificare il suovalore in formato testuale al suo interno.Nella prossima lezione illustreremo come utilizzare lelemento <progress> e la sua utilità nel caricarei contenuti dei documenti web.Tabella del supporto sui browserNuovi tag semantici e strutturali<meter> No No No 8.0+ 11.0+ ProgressFunzioni e dati tecniciLelemento <progress> rappresenta lo stato di completamento di un compito e può essere didue tipi: indeterminato: indica che il compito (task) è in fase di completamento, ma che non è chiaro quanto ancora resta da fare prima che loperazione sia completata (ad esempio perché loperazione è in attesa della risposta di un host remoto); determinato quando è possibile ricavare un numero quantificabile nel range da zero a un massimo, in modo da ottenere la percentuale di lavoro completato rispetto al totale(ad esempio un preloader di unimmagine).Esistono due attributi che determinano lo stato di completamento dellattivita del tag <progress>.
  • 46. Lattributo value, che specifica la quantità di lavoro completata, e lattributo max, che specifica laquantità di lavoro richiesta in totale. Le unità sono arbitrarie e non specificate.Tuttavia, i valori passati come attributi del tag <progress> non sono renderizzati e quindidovrebbero comunque essere inseriti in forma testuale nellHTML in modo da poter fornire unfeedback più preciso agli utenti; inoltre questo elemento attualmente non viene renderizzato dallamaggior parte dei browser ed è quindi ancora sconsigliato il suo utilizzo.<section> <p>Caricamento: <progress id="mioLoader" max="100" value="30"><span>30</span>%</progress></p></section>Vediamone adesso un esempio concreto in questa demo(http://www.html.it/guide/esempi/html5/esempi/lezione_progress/progress.html) (funziona nelle piùrecenti versioni di Opera e Google Chrome).Gli attributi value e max, se presenti, devono essere valori validi (http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-floating-point-number).Lattributovalue, se presente, deve avere un valore uguale o maggiore di zero e minore o uguale alvalore dellattributo max, se presente, o 1.0, in caso contrario. Lattributo max, se presente, deveavere un valore maggiore di zero.Ovviamente, lelemento <progress> deve essere utilizzato solamente per indicare lo stato in fase diprogressione di un compito; per indicare quantitativamente la misura di unoggetto o di uno stato nonin progressione bisogna utilizzare lelemento <meter>(http://xhtml.html.it/guide_preview/lezione/4976/meter/).Data la complessità dellargomento e la costante variazione delle specifiche a riguardo consigliamo diconsultare il sito del WHATWG (http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#the-progress-element) per un maggiore approfondimento.Nella prossima lezione descriveremo brevemente gli altri tag semantici introdotti nella specificaHTML5.Tabella del supporto sui browserNuovi tag semantici e strutturali<progress> No No No 8.0+ 11.0+ Altri tagAbbiamo scelto di riassumere brevemente in ununica lezione diversi tag in quanto il costanteaggiornamento delle specifiche non ci consente di poterli descrivere dettagliatamente, almeno sino aquando queste ultime non saranno rilasciate ufficialmente; inoltre, ne sconsigliamo lutilizzoalmeno sino a quando i browser non inizieranno a supportarli in maniera standard.
  • 47. I tag <figure> e <figcaption>Nellelemento <figure> possiamo racchiudere dei contenuti, opzionalmente con una didascalia(<figcaption>), che rappresentano delle singole unità indipendenti rispetto al contenuto principale;ad esempio possiamo utilizzare lelemento <figure> per annotare le illustrazioni, schemi, foto,elenchi di codice, etc... ovvero tutto ciò che fa parte del contenuto principale ma che potrebbe essereanche allontanato dallo stesso senza intaccarne il senso.Lelemento <figcaption> quindi rappresenta una didascalia o una leggenda per lelemento <figure>padre.Esempio:<figure><img src="benevenuti.jpg" alt=""> <figcaption> Foto di benvenuto <small>© Diritti riservati</small> </figcaption></figure>È importante notare che lattributo alt è vuoto poiché limmagine è descritta nel tag <figcaption>ed è stato usato il tag <small> per il copyright.Il tag <embed>Lelemento <embed> è già utilizzato da anni per inserire nel codice HTML contenuti interattivi omultimediali (tipicamente Flash, Quicktime, etc.). Questo elemento, però, era stato deprecato nellespecifiche HTML 4 in favore del tag <object>. Ora è stato reintrodotto perché, nonostante la potenzadelle nuove API HTML5, si pensa che al momento non tutto ciò che si riesce ad ottenere con plug-in diterze parti possa essere realizzato in HTML5. Inoltre, si è cercato di mantenere la retrocompatibilitàcon applicazioni basate sullutilizzo di questo elemento.Il tag <ruby>Il tag <ruby> è usato per specificare le annotazioni Ruby, che vengono utilizzate nella tipografiaorientale in combinazione con il testo principale.Il tag <wbr>Il tag <wbr> definisce dove, in una parola, sarebbe opportuno aggiungere un a capo. Infatti, quandouna parola è lunga, utilizzando lelemento <wbr> il browser comprenderà dove eventualmente saràpossibile inserire un a capo.I tag <command> e <menu>Entrambi sono elementi molto interessanti: permettono di definire barre degli strumenti o menu discelta rapida per le nostre applicazioni, con le icone e i relativi comandi che possono essere eseguitida script.Il tag <command> rappresenta unazione che lutente può richiamare in qualche modo. Esso èvisibile solo se inserito allinterno di un elemento <menu>. In caso contrario, non verrà visualizzato,
  • 48. ma può essere utilizzato per specificare un tasto di scelta rapida.Al momento nessun browser supporta questi tag.I tag <details> e <summary>I tag <details> e <summary> rappresentano un widget informativo da cui lutente può ottenereinformazioni supplementari o controlli aggiuntivi. Nel tag <summary>,che è contenuto all interno deltag<details>, deve essere inserita una sintesi del contenuto del widget o anche una legenda. Icontenuti dellelemento <details> possono essere mostrati o meno dal browser grazie allattributoopen, di tipo booleano. Anche questi tag non sono supportati ancora da nessun browser.Il tag <keygen>Lelemento <keygen> rappresenta un generatore di chiavi numeriche allinterno di un form. Quandosi effettua linvio di un form contenente il tag <keygen>, la chiave privata viene memorizzata nelkeystore locale e la chiave pubblica viene confezionato e inviata al server.Lelemento è già supportato da diversi browser ma manca il suo supporto in IE.Il tag <output>Lelemento <output> ci restituisce il risultato di un calcolo.Tabella del supporto sui browserNuovi tag semantici e strutturali<figure> 9.0+ 4.0+ Nightly build Nightly build 11.0+<figcaption> 9.0+ 4.0+ Nightly build Nightly build 11.0+<ruby> 5.5+ No 5.0+ 5.0+ No<wbr> No No No No No<command> No No No No No<menu> No No No No No<details> No No No No No<summary> No No No No No<keygen> No 1.0+ 2.0+ 2.0+ 7.0+<output> No 4.0+ Nightly build Nightly build 9.0+ I form in HTML5: una panoramicaQuando Javascript fu introdotto nelle pagine web, fu subito implementato per assolvere a duecompiti: il rollover delle immagini e la validazione dei form.Mentre il primo era un mero problema visuale (e in parte anche di usabilità), il secondo utlizzocomune di Javascript era necessario perché permetteva di eliminare (o per meglio dire arginare)linvio di form mal compilati o con errori, evitando allutente lattesa non necessaria tra il linvio,
  • 49. leventuale fallita validazione dei dati inviati e il conseguente reload della pagina.Ovviamente nessun programmatore esperto si fida di quello che "arriva" dai form. Si rendenecessario, quindi, il controllo lato server dei dati inviati. Nonostante questo, limplementazione dicontrolli client side è una prassi comune.Con HTML5 avviene per la validazione e in generale per linterazione tramite i moduli, quello che èaccaduto con elementi come video e audio. La specifica introduce funzionalità e tecniche chepermettono allo sviluppatore da affidarsi unicamente al linguaggio di markup, senza dove ricorrere aJavascript o a plugin esterni.Quello che andremo a descrivere nelle prossime lezioni era originariamente parte della specifica delWHATWG chiamata Web Form 2.0 (http://www.whatwg.org/specs/web-forms/current-work/),aggiornamento della specifica del W3C denominata Web Form 1.0(http://www.w3.org/TR/html4/interact/forms.html).Attualmente Web Form 2.0 è un progetto chiuso in quanto ora si lavora sulla parte dedicata ai form(http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html) della specifica HTML5.Lavorare con i form è stato finora molto semplice: si inizia tutto con il tag <form>, si prosegue con gli<input type="text">, a volte con gli <input type="password"> e magari con una <textarea> ouna<select> o <input type="radio">, e si finisce sempre con <input type="submit">.Questi tipi di input, però, non si adattano alla varietà di dati possibilmente richiesti. Spesso citroviamo a richiedere indirizzi e-mail, numeri di telefono, date e molti altri tipi di dati ancora.Non solo, ci sono anche le validazioni di consistenza derivate da questi dati, per esempio il fatto chelindirizzo e-mail deve contenere la @ o che le date devono essere in un formato preciso, oltre avalidazioni dipresenza e obbligatorietà. È soprattutto a questo livello, come si accennava, cheentravano in gioco Javascript e le validazioni client side.Tutto questo con HTML5 finisce grazie allinserimento nella specifica di nuovi type come email,number, range, search e di diversi nuovi attributi come placeholder, autofocus, require, min, max,etc.Questi nuovi tipi di input e attributi sono molto apprezzati dalla comunità dei programmatori perch´oltre a fornire un aumento dellaccessibilità dei form (anche in ambito mobile) sono pronti per luso.Non tutti funzionano perfettamente su tutti i browser, ma senza nessun hack, senza Javascript che necontrolla il funzionamento, degradano bene, anche in preistorici browser.Possiamo allora iniziare. Nuovi attributi per i form: autofocus, placeholder e formI tipi di attributiPrima di iniziare cominciamo con il dire che esistono diversi tipi di attributi per i tag HTML. Nelparticolare: Attributi booleani: questi tipi di attributi hanno due stati, lo stato vero e lo stato falso. Il primo è rappresentato dalla presenza dellattributo mentre il secondo, lo stato falso, è rappresentato dalla sua assenza. Il valore dellattributo, quindi, non è necessario (es. disabled) anche se sono accettati comunque alcuni valori. Nello specifico possiamo valorizzarlo con una stringa vuota (es.disabled="") oppure con il nome dellattributo senza
  • 50. spazi iniziali o finali (es. disabled=disabled o disabled="disabled"). Attributi enumerati: questi tipi di attributi possono prendere come valore un insieme finito di parole chiavi (es. lattributo type per il tag ul può assumere i valori disc, square e circle). A volte le parole chiave possono avere sinonimi. Una parola chiave potrebbe essere anche "", cioè il valore nullo. Attributi generici: questo tipo di attributo, invece, può prendere qualsiasi valore. Esempi di questi attributi sono class, id e placeholder.Dopo questa premessa vediamo subito allopera i primi tre dei nuovi attributi per i form definiti inHTML5: autofocus, placeholder e form.autofocusLattributo autofocus è un attributo booleano e serve a impostare il focus su uno specificoelemento del form appena la pagina è caricata. Un esempio canonico è quello della home page diGoogle: appena viene caricata il focus è automaticamente impostato sul campo per la ricerca.Ovviamente solo un elemento per pagina può avere lattributo autofocus.Questo attributo deve essere usato con parsimonia in quanto alcuni utenti, come quelli che usano labarra spaziatrice per scorrere la pagina, potrebbero trovare questa costrizione fastidiosa, preferendoun atteggiamento più soft.È per questo motivo che autofocus dovrebbe essere usato solo nelle pagine che contengonosolamente (o principalmente) form (come per esempio pagine di login o di ricerca).Esempi duso dellattributo autofocusEcco comunque un esempio pratico:<form action="/" method="get"> <input type="text" name="myname" id="myid" autofocus> <input type="submit" value="Invia"></form>Alternative per limplementazione dellattributo autofocusPer far sì che lattributo autofocus funzioni su tutti i browser è sufficiente modificare il codice inquesto modo:<form action="/" method="get"> <input type="text" name="myname" id="myid" autofocus > <script> if (!("autofocus" in document.createElement("input"))) { document.getElementById("myid").focus(); } </script> <input type="submit" value="Invia" ></form>
  • 51. placeholderIl valore dellattributo placeholder è visualizzato allinterno di un input, o di una textarea, finquando il campo è vuoto e non guadagna il focus (tramite il click o spostandosi su di esso il tastoTab).Semanticamente lattributo placeholder dovrebbe essere valorizzato con valori accettabili dal form,dovrebbe, in altre parole, contenere un esempio di ciò che lutente andrà a scrivere nel campo.Spesso il placeholder viene utilizzato erroneamente al posto della label descrivendo quindi cosadovrebbero inserire.Esempi duso dellattributo placeholderAllinterno del nostro progetto guida si fa molto uso dellattributo placeholder. Per esempio:<form name="ricerca" method="post" action="/search"> <label> Parola chiave: <input type="search" autocomplete="on" placeholder="article, section, ..." name="keyword" required maxlength="50"> </label> <input type="submit" value="ricerca"></form>Creando un risultato come nella seguente immagine:Figura 17 - Resa visiva di un input con lattributo placeholderAlternative per limplementazione dellattributo placeholderNon sarà semplice scrivere una funzione che faccia funzionare il placeholder su tutti i browser e pertutti gli input, ma data la natura dellattributo non dovrebbe essere nemmeno necessario.Ad ogni modo, se volessimo farlo funzionare su tutti i browser, avremmo diverse soluzioni, alcune piùsemplici altre più complesse.Proponiamo qui lalternativa proposta da Andrew January sul suo blog(http://www.morethannothing.co.uk/2010/01/placeholder-text-in-html5-a-js-fallback/).Nello script placeholder.js(http://www.html.it/guide/esempi/html5/esempi/lezione_placeholder/placeholder.js) abbiamomodificato i commenti mettendoli in italiano di modo che sia di più facile comprensione. Per farlofunzionare si ricordi di includere la libreria jQuery nella pagina.formUn nuovo attributo che si può inserire in tutti gli input è appunto form, anche se sfortunatamentenon è molto supportato e non esiste una vera e propria alternativa.Questo nuovo attributo serve per specificare a quale form, o a quali form, linput fa riferimento.
  • 52. Richiede come valore lid del form a cui vogliamo che faccia riferimento, o nel caso di più form, gliidseparati da uno spazio, " ".Esempi duso dellattributo formEcco comunque un esempio pratico:<form action="/" method="get" id="myFormId"> <input type="text" name="myname"> <input type="submit" value="Invia"></form><input type="text" name="mysurname" form="myFormId">Nonostante linput con id mysurname sia fuori dal form, inviando il form inviamo anche il suo valoregrazie al suo attributo form.Luso di questo attributo è sconsigliato a meno di non conoscere con certezza il browser dellutenteche utilizzarà la nostra applicazione.Alternative per limplementazione dellattributo formCome detto nella descrizione dellattributo, non cè una vera e propria alternativa. Siamo di fronte adue soluzioni: La prima è quella di agire sul DOM e spostare gli elementi interessati allinterno del form. La seconda è quella di assegnare una funzione al submit del form che cerchi i valori degli input interessati e per ognuno di questi inserire nel DOM degli <input type="hidden"> e quindi procedere con linvio.Tabella del supporto sui browserForm: nuovi attributiautofocus No 4.0+ 4.0+ 2.0+ 9.0+placeholder No 4.0+ 4.0+ 2.0+ 11.0+form No 4.0+ Nightly build Nightly build 9.0+ Nuovi attributi dei form per la validazioneLa validazione dei form è forse largomento relativo ai form più importante. Vediamo subito indettaglio che cosa ci propone la nuova specifica HTML5.requiredrequired è un attributo booleano e serve a rendere obbligatoria la compilazione dellelementoa cui è applicato. La condizione viene valutata al submit del form.Ecco un esempio di utilizzo:
  • 53. <form name="commenti" method="post" action="/141/comments"> [...] <label>Messaggio: <textarea name="messaggio" placeholder="Scrivi qui il tuo messaggio (max 300 caratteri)" maxlength="300" required></textarea> </label> [...] <input type="reset" value="Resetta il form"> <input type="submit" value="Invia il commento"></form>autocompleteAnche se questo attributo non è esattamente un attributo per le validazioni, abbiamo deciso diinserirlo in questa lezione in quanto previene un comportamento dei browser non sempre voluto:spesso i browser riempiono i campi da inserire in maniera automatica.Questo comportamento è nella maggior parte dei casi un comportamento comodo, però in alcuni casiè fastidioso. Si pensi per esempio ai campi password o ai campi del codice della banca: probabilmentenon vogliamo che il browser li completi in automatico.Ecco che arriva in nostro soccorso lattributo autocomplete che è un attributo enumerato. Inparticolare i valori che accetta sono: on: indica che il valore non è particolarmente sensibile e che il browser può compilarlo in maniera automatica; off: indica che il valore è particolarmente sensibile o con un tempo di scadenza (il codice di attivazione di un servizio, per esempio) e che quindi lutente deve inserirlo manualmente ogni volta che lo compila; nessun valore: indica in questo caso di usare il valore di default scelto dal browser (normalmente on).Ecco un esempio di utilizzo:<form name="commenti" method="post" action="/141/comments"> [...] <label>Nick: <input type="text" name="nickname" autocomplete="on" required pattern="[a-z]{1}[a-z_]{2,19}" title="Un nickname è composto da lettere minuscole e _; Sono consentiti da 3 a 20 caratteri." placeholder="your_nickname"> </label> [...] <input type="reset" value="Resetta il form"> <input type="submit" value="Invia il commento"></form>multiple
  • 54. In molti casi abbiamo bisogno che lutente possa inserire più valori per lo stesso input (peresempio se gli stiamo chiedendo gli indirizzi e-mail di amici a cui inviare un invito).Ecco che arriva in nostro soccorso lattributo multiple che è un attributo booleano.Un esempio di utilizzo:<form> <label>eMail a cui inviare linvito: <input type="email" multiple name="friendEmail" </label> [...] <input type="reset" value="Resetta il form"> <input type="submit" value="Invia"></form>patternIn molti casi abbiamo bisogno di validare un determinato input verificando che il valore inseritosottostia a determinate regole di creazione (per esempio potremmo volere che il campo password noncontenga spazi).Possiamo contare in questi casi sullattributo pattern.Il valore di pattern, se specificato, deve essere una espressione regolare valida (http://www.ecma-international.org/publications/standards/Ecma-262.htm).Se viene indicato lattributo pattern bisognerebbe indicare anche il title per dare una descrizionedel formato richiesto, altrimenti il messaggio di errore sarà generico e probabilmente di poco aiuto.Ecco un esempio di utilizzo:<form name="commenti" method="post" action="/141/comments"> [...] <label>Nick: <input type="text" name="nickname" autocomplete="on" required pattern="[a-z]{1}[a-z_]{2,19}" title="Un nickname è composto da lettere minuscole e _; Sono consentiti da 3 a 20 caratteri." placeholder="your_nickname"> </label> [...] <input type="reset" value="Resetta il form"> <input type="submit" value="Invia il commento"></form>In questo esempio si sta richiedendo che lo username sia una parola in minuscolo composta solo dalettere e da "_", di una lunghezza minima di 3 caratteri e massima di 20 e che non cominci con "_"min e max
  • 55. I valori min e max descrivono rispettivamente il valore minimo e massimo consentito.Il valore di max deve essere maggiore del valore di min se indicato.Questi attributi si applicano sia alle date (come detetime(http://xhtml.html.it/guide_preview/lezione/4986/nuovi-tipi-di-input-per-la-gestione-delle-date/),date(http://xhtml.html.it/guide_preview/lezione/4986/nuovi-tipi-di-input-per-la-gestione-delle-date/), month (http://xhtml.html.it/guide_preview/lezione/4986/nuovi-tipi-di-input-per-la-gestione-delle-date/)) sia ai numeri (number (http://xhtml.html.it/guide_preview/lezione/4987/input-type-number/) e range (http://xhtml.html.it/guide_preview/lezione/4988/input-type-range/)). Permaggiore dettagli rimandiamo alle lezioni che trattano in maniera specifica questi nuovi tipi di input.Ecco un esempio di utilizzo:<form name="commenti" method="post" action="/141/comments"> [...] <label>Età: <input type="number" name="age" min="13" max="130" step="1"> </label> [...] <input type="reset" value="Resetta il form"> <input type="submit" value="Invia il commento"></form>In questo caso stiamo chiedendo unetà compresa tra i 13 e i 130 anni (estremi compresi).stepIl valore step definisce la distanza che intercorre tra un valore e il successivo. Definisce, in altreparole, la granularità dei valori permessi.Il valore di step deve essere un valore positivo non nullo.Questo attributo si applica sia alle date (come detetime, date, month) sia ai numeri (number erange).Ecco un esempio di utilizzo:<form name="commenti" method="post" action="/141/comments"> [...] <label>Età: <input type="number" name="age" min="13" max="130" step="1"> </label> [...] <input type="reset" value="Resetta il form"> <input type="submit" value="Invia il commento"></form>In questo caso stiamo chiedendo solo valori interi.novalidate
  • 56. Questo attributo si applica al tag form e permette di saltare tutte le validazioni dei tag che da essodiscendono.novalidate è un attributo booleano.Ecco un esempio di utilizzo:<form novalidate> <label>Età: <input type="email" name="myEmail" required> </label> <input type="reset" value="Resetta il form"> <input type="submit" value="Invia"></form>In questo caso non verrà controllato che il campo email sia in un formato valido né che sia presente.Tabella del supporto sui browserForm: nuovi attributiautocomplete No No No No 10.6+min, max No No Nightly build Nightly build 9.0+multiple No 3.6+ 4.0+ 2.0+ 11.0+pattern No 4.0+ 4.0+ 2.0+ 9.0+required No 4.0+ 4.0+ 2.0+ 9.0+step No No 4.0+ 2.0+ 9.0+ Input type: telÈ possibile utilizzare lelemento input con type=tel per creare un campo adatto allinserimentodi numeri di telefono.A differenza degli input di tipo email (http://xhtml.html.it/guide_preview/lezione/4985/input-type-email/) e url (http://xhtml.html.it/guide_preview/lezione/4984/input-type-url/), questo tipo nonimpone un particolare formato. Ciò è intenzionale. In pratica, i campi di numero di telefono sonocampi liberi, perché, a livello intenzionale, i numeri possono essere scritti in diversi modi. È comunquepossibile usare lattributo pattern (http://xhtml.html.it/guide_preview/lezione/4981/nuovi-attributi-dei-form-per-la-validazione/) per forzare un determinato formato.I dispositivi mobili e il type telI dispositivi mobili possono presentare tastiere personalizzate per facilitare linserimento comemostrato nelle immagini che seguono (la prima è relativa a iPhone/iOS, mentre la seconda a unsistema Android).Figura 18 - Tastiera iPhone
  • 57. Figura 19 - Tastiera AndroidEsempi dusoLesempio è molto semplice, eccolo:<form> <label>Inserisci il tuo numero di telefono: <input type="tel" name="myTelephone"> </label> <input type="submit" value="Invia" ></form>Questo codice produce visivamente un normale <input type="text">.Tabella del supporto sui browserForm: nuovi tipi di input
  • 58. tel No 4.0+ 4.0+ 2.0+ 11.0+ Input type: searchÈ possibile utilizzare lelemento input con type=search per creare un campo di ricerca. Questocampo è, ovviamente, un campo libero nel senso che non impone nessun pattern.Safari su Mac OS X e il type searchNella maggior parte dei browser non cè alcuna differenza tra un campo di tipo text e un camposearch, ma in Safari su Mac OS X abbiamo un comportamento particolare: 1. Visivamente linput ha i bordi arrotondati. 2. Se scriviamo qualcosa nel campo compare una piccola X sulla destra che, se cliccata, svuota il campo.Figura 1Esempi dusoEcco un semplice esempio per implementare questo tipo di input:<form name="ricerca" method="post" action="/search"> <label> Parola chiave: <input type="search" autocomplete="on" placeholder="article, section, ..." name="keyword" required maxlength="50"> </label> <input type="submit" value="Ricerca"></form>Come detto precedentemente, questo codice nella maggior parte dei browser produce visivamente unnormale <input type="text">.Tabella del supporto sui browserForm: nuovi tipi di inputsearch No 4.0+ 2.0+ 2.0+ 11.0+ Input type: urlSi usa lelemento input con type=url per creare un campo destinato allinserimento di un
  • 59. indirizzo web.Il tipo url, se specificato, dovrebbe rappresentare linserimento di un URL assoluto, ovvero nelformato http://www.sito.com/etc.... Nel caso in cui il valore inserito non sia valido, vienesollevata, nei browser che supportano il tipo url, uneccezione che non riconosce il pattern.I dispositivi mobili e il type urlI dispositivi mobili possono presentare tastiere personalizzate per facilitare linserimento. iPhonemodifica la sua tastiera eliminando la barra spaziatrice e mettendo il punto, la slash e lestensione".com" come visualizzato nella figura sottostante. Android, invece, visualizza attualmente la tastierastandard.Figura 21 - Tastiera iPhone con un campo di tipo urlEsempi dusoLesempio è molto semplice, eccolo:<form name="commenti" method="post" action="/141/comments"> [...] <label> Www: <input type="url" name="url" autocomplete="on" placeholder="http://mywebsite.com"> </label> [...] <input type="reset" value="Resetta il form"> <input type="submit" value="Invia il commento"></form>Produce visivamente un normale <input type="text">.Tabella del supporto sui browserForm: nuovi tipi di inputurl No 4.0+ 4.0+ 2.0+ 9.0+
  • 60. Input type: emailLelemento input con type=email viene usato per creare un campo per inserire un indirizzo e-mail.Linput con tipo email, se specificato, dovrebbe rappresentare linserimento di indirizzi e-mail. Unafondamentale condizione di validità, dunque, sarà rappresentata dalla presenza del simbolo @. Nelcaso in cui il valore inserito non sia valido viene sollevata uneccezione.I dispositivi mobili e il type emailI dispositivi mobili possono presentare, anche in questo caso, tastiere ad hoc. iPhone modifica la suatastiera mostrando la chiocciola e il punto come visualizzato in figura 22. Android attualmentevisualizza la tastiera standard.Figura 22 - Tastiera iPhone con un campo di tipo emailEsempi dusoAnche per questo tipo di input presentiamo un piccolo snippet di codice:<form name="commenti" method="post" action="/141/comments"> [...] <label> Email: <input type="email" name="email" autocomplete="on" placeholder="email@domain.ext"> </label> [...] <input type="reset" value="Resetta il form"> <input type="submit" value="Invia il commento"></form>Il codice visto produce visivamente un normale <input type="text">.
  • 61. Tabella del supporto sui browserForm: nuovi tipi di inputemail No 4.0+ 4.0+ 2.0+ 9.0+ Nuovi tipi di input per la gestione delle dateTutti i programmatori prima o poi hanno avuto a che fare con la gestione delle date, con tutti iproblemi che ne conseguono. HTML5 mette a disposizione nuovi tipi di input concepiti per facilitare ilcompito dei programmatori nellinserimento di date da parte degli utenti.Dal momento che ci sono diversi tipi di date di cui potremmo aver bisogno, ecco che sono statiimplementati nella specifica diversi tipologie. In particolare: datetime: gestisce sia la data che lora (con fuso orario); datetime-local: gestisce sia la data che lora (senza fuso orario); date: gestisce le date; month: gestisce i mesi; week: gestisce le settimane; time: gestisce lora.Per tutti questi input abbiamo degli attributi specifici che sono: min: che rappresenta il minimo valore accettato; max: che rappresenta il massimo valore accettato; step: che rappresenta la granulosità dei valori accettati.Vediamoli nel dettaglio.datetimeCome detto, serve per permettere linserimento di date e ore in un solo colpo. Visivamente neibrowser che lo supportano (pochi per ora) abbiamo la generazione di un datepicker in cui abbiamo lapossibilità di selezionare un giorno e con lopzione di mettere anche lora, come nellimmagine quisotto. Ecco cosa avviene quando clicchiamo su quella che sembra essere una select (lo screenshot èdi Opera 11):Figura 23 - Input datetime su Opera
  • 62. Nei sistemi che non supportato il tipo datetime, viene generato un normale input di testo.Vediamo un esempio di codice<form> <label>Quando sei disponibile per un incontro? <input type="datetime" name="mydatetime"> </label> <input type="reset" value="Resetta il form"> <input type="submit" value="Invia"></form>Gli attributi specifici min: il valore di questo attributo deve essere una data e ora con il fuso orario valida (http://developers.whatwg.org/common-microsyntaxes.html#valid-global-date-and-time- string). max: il valore di questo attributo deve essere una data e ora con il fuso orario valida (http://developers.whatwg.org/common-microsyntaxes.html#valid-global-date-and-time- string) e deve essere maggiore del valore dellattributo min se specificato. step: il valore di questo attributo deve essere un intero e rappresenta i secondi. Il valore di default è di 60 secondi.datetime-localÈ del tutto simile a datetime, con lunica differenza che non vengono passate informazioni sul fusoorario.Ecco come appare su Opera 11:Figura 24 - Input datetime-local su Opera
  • 63. Nei sistemi che non supportato il datetime-local viene generato un normale input type="text".Esempio:<form> <label>Quando sei disponibile per un incontro? <input type="datetime-local" name="mydatetime"> </label> <input type="reset" value="Resetta il form"> <input type="submit" value="Invia"></form>Gli attributi specifici min: il valore di questo attributo deve essere una data e ora valida (http://developers.whatwg.org/common-microsyntaxes.html#valid-local-date-and-time- string). max: il valore di questo attributo deve essere una data e ora valida (http://developers.whatwg.org/common-microsyntaxes.html#valid-local-date-and-time-string) e deve essere maggiore del valore dellattributo min se specificato. step: il valore di questo attributo deve essere espresso in secondi. Il valore di default è di 60 secondi.dateServe per inserire una data. Nei browser che lo supportano si ottiene un datepicker in cui abbiamo lapossibilità di selezionare un giorno:Figura 25 - Input date su Opera
  • 64. Nei sistemi che non supportato il tipo date viene generato un normale campo di testo.Esempio:<form> <label>Quando sei disponibile per un incontro? <input type="date" name="mydatetime"> </label> <input type="reset" value="Resetta il form"> <input type="submit" value="Invia"></form>Gli attributi specifici min: il valore di questo attributo deve essere una data valida (http://developers.whatwg.org/common-microsyntaxes.html#valid-date-string). max: il valore di questo attributo deve essere una data valida (http://developers.whatwg.org/common-microsyntaxes.html#valid-date-string) e deve essere maggiore del valore dellattributo min se specificato. step: il valore di questo attributo deve essere espresso in giorni. Il valore di default è di 1 giorno.monthServe per permettere di selezionare un mese dellanno. In figura 4 il datepicker per selezionare unmese generato su Opera 11:Figura 26 - Input month su OperaNei sistemi che non supportato month viene generato un normale campo di testo.Esempio<form> <label>Quando sei disponibile per un incontro? <input type="month" name="mydatetime"> </label> <input type="reset" value="Resetta il form"> <input type="submit" value="Invia"></form>
  • 65. Gli attributi specifici min: il valore di questo attributo deve essere un mese valido (http://developers.whatwg.org/common-microsyntaxes.html#valid-month-string). max: il valore di questo attributo deve essere una mese valido (http://developers.whatwg.org/common-microsyntaxes.html#valid-month-string) e deve essere maggiore del valore dellattributo min se specificato. step: il valore di questo attributo deve essere espresso in mesi. Il valore di default è di 1 mese.weekViene usato per la selezione di una determinata settimana dellanno (composta da anno - numero disettimana). In figura 5 il widget prodotto dallinserimento di questo tipo di input su Opera 11:Figura 27 - Input week su OperaNei sistemi che non supportato week viene creato un normale campo di testo.Esempio:<form> <label>Quando sei disponibile per un incontro? <input type="week" name="mydatetime"> </label> <input type="reset" value="Resetta il form"> <input type="submit" value="Invia"></form>Gli attributi specifici min: il valore di questo attributo deve essere una settimana valida (http://developers.whatwg.org/common-microsyntaxes.html#valid-week-string). max: il valore di questo attributo deve essere una settimana valida (http://developers.whatwg.org/common-microsyntaxes.html#valid-week-string) e deve essere maggiore del valore dellattributo minse specificato. step: il valore di questo attributo deve essere espressa in settimane. Il valore di default è di 1 settimana.timeServe per selezionare e inserire una determinata ora del giorno. Ancora una schermata da Opera 11:
  • 66. Figura 28 - Input time su OperaNei sistemi che non supportato il time genera un normale input type="text".Vediamo un esempio di codice<form> <label>Quando sei disponibile per un incontro? <input type="time" name="mydatetime"> </label> <input type="reset" value="Resetta la form"> <input type="submit" value="Invia"></form>Gli attributi specifici min: il valore di questo attributo deve essere una ora valida (http://developers.whatwg.org/common-microsyntaxes.html#valid-time-string). max: il valore di questo attributo deve essere una ora valida (http://developers.whatwg.org/common-microsyntaxes.html#valid-time-string) e deve essere maggiore del valore dellattributo min se specificato. step: il valore di questo attributo deve essere espresso in secondi. Il valore di default è di 60 secondi.Tabella del supporto sui browserForm: nuovi tipi di inputdatetime No No Parziale Parziale 9.0+date No No Parziale Parziale 9.0+month No No Parziale Parziale 9.0+week No No Parziale Parziale 9.0+time No No Parziale Parziale 9.0+datetime-local No No Parziale Parziale 9.0+ Input type: numberÈ possibile utilizzare lelemento input con type=number per creare un campo destinatoallinserimento di un numero.I dispositivi mobili e il type numberI dispositivi mobili possono presentare tastiere personalizzate per facilitare linserimento comemostrato nelle immagini che seguono (fanno riferimento, rispettivamente, a iPhone/iOS e Android).
  • 67. Figura 29 - Tastiera iPhone con un input di tipo numberFigura 30 - Tastiera Android con un input di tipo numberAttributi specifici per il type numberHTML5 mette a disposizione un set di attributi specifici per i campi di tipo number. Servono aspecificare delle limitazioni per il valore di questo attributo. Questi attributi sono min, max e step.Attributo minSpecifica il minimo valore permesso. La sintassi è semplice: min="1" permette solo linserimento dinumeri positivi. I valori permessi sono, ovviamente, numeri.Attributo maxSpecifica il massimo valore permesso. max="10" permette solo linserimento di numeri inferiori ouguali a 10. Il valore di questo attributo deve essere maggiore del valore dellattributo min (sespecificato).Attributo step
  • 68. Lattributo step indica la granulosità che deve avere il valore, limitando i valori permessi. Il valore distep se specificato deve essere un numero (anche non intero) maggiore di zero oppure la stringa"any" (che equivale a non inserire lattributo).La sintassi è anche in questo caso molto semplice: step=3 influenza i valori permettendo valori come-3, 0, 3, 6 ma non -1 o 2.Esempi dusoUn esempio potrebbe avere questa forma:<form name="commenti" method="post" action="/141/comments"> [...] <label>Età: <input type="number" name="age" min="13" max="130" step="1"> </label> [...] <input type="reset" value="Resetta il form"> <input type="submit" value="Invia il commento"></form>In questo caso stiamo chiedendo di inserire unetà compresa tra i 13 e i 130 anni (estremi compresi)e i valori accettati sono interi.Nella maggior parte dei browser si produce attualmente un normale <input type="text">, ma neibrowser che supportano number abbiamo:Figura 31 - Un input di tipo numberTabella del supporto sui browserForm: nuovi tipi di inputnumber No No 4.0+ 2.0+ 9.0+ Input type: rangeMolto simile semanticamente allinput type=number(http://xhtml.html.it/guide_preview/lezione/4987/input-type-number/), questo nuovo tipo di inputpermette agli utenti di inserire un numero tramite uno slider.Attributi specificiHTML5 mette a disposizione un set di attributi specifici per il tipo range (che sono gli stessi deltype=number): servono a specificare delle limitazioni per il valore di questo attributo. Questi attributi
  • 69. sono min,max e step. min: specifica il minimo valore permesso. Esempio: min="1", che permette solo di passare numeri da 1 in su. max : specifica il massimo valore permesso. Esempio: max="10", che permette solo di inviare numeri inferiori o uguali a 10. Il valore di questo attributo deve essere maggiore del valore dellattributo min (se specificato). step: indica la granulosità che deve avere il value limitando i possibili valori passati. Il valore di step se specificato deve essere un numero (anche non intero) maggiore di zero oppure la stringa "any" (che equivale a non inserire lattributo). Esempio: step=3, che influenza i valori inseriti passando valori come -3, 0, 3, 6.Esempi dusoLesempio è molto semplice, eccolo:<form name="commenti" method="post" action="/141/comments"> [...] <label>Voto: <input type="range" name="voto" min="0" max="5" step="1"> </label> [...] <input type="reset" value="Resetta il form"> <input type="submit" value="Invia il commento"></form>Ecco come appare un input di tipo range sui browser che lo supportano:Figura 32 - Un input di tipo rangeTabella del supporto sui browserForm: nuovi tipi di inputrange No No 4.0+ 2.0+ 9.0+ Input type: colorLelemento input con type=color dovrebbe creare un color picker, quel tipo particolare di widgetutile per la selezione di un colore a partire da una palette di colori. Una volta selezionato ilcolore, il campo passa alla nostra pagina di ricezione un colore RGB esadecimale composto da 6 cifre.Questo tipo input ad oggi non è molto supportato. Per la sua implementazione sui nostri siti si puòperò ricorrere ad una qualsiasi delle tante soluzioni Javascript disponibili.
  • 70. Opera e il type colorNella maggior parte dei browser non cè alcuna differenza tra un campo di tipo text e un campocolor, ma su Opera abbiamo un comportamento particolare: 1. Visivamente abbiamo una select particolare con i colori (esempio in figura 33). 2. Se clicchiamo abbiamo una scelta dei colori base (esempio in figura 34). 3. Se clicchiamo su "Altro" richiamiamo il color picker di sistema (esempio su Opera su Mac OS X in figura 35).Figura 33 - Input color su Opera: stato inizialeFigura 34 - Input color su Opera: selezione del coloreFigura 35 - Input color su Opera: color-picker di sistemaEsempi dusoUn input di tipo color si crea così:<form> <label>Seleziona il colore di sfondo:
  • 71. <input type="color" name="mybackground"> </label> <input type="reset" value="Resetta la form"> <input type="submit" value="Invia"></form>Tabella del supporto sui browserForm: nuovi tipi di inputcolor No No Parziale Parziale 11.0+ Cosa sono le datalist?Lelemento HTML5 <datalist> è utilizzato per fornire una funzione di "completamento automatico"ad un elemento del form. Permette, in altre parole, di fornire allutente un elenco di opzionipredefinite da cui scegliere, offrendo al contempo la possibilità di inserire un valore non presenteinizialmente nella lista.Mette insieme i vantaggi di una select e di un input di testo. Sfortunatamente questo tag moltoutile è al momento poco supportato dai browser (solo Opera lo supporta).Datalist su OperaNella maggior parte dei browser il codice relativo allelemento datalist viene completamente ignoratoma su Opera abbiamo il seguente comportamento: 1. Visivamente abbiamo solo il nostro input e la datalist non è renderizzata in nessun modo (figura 36). 2. Se clicchiamo sullinput a cui la datalist è collegata, vengono presentate le opzioni della datalist (figura 37). 3. Se clicchiamo su unopzione, linput a cui la datalist è collegato assume il valore dellopzione (figura 38).Figura 36 - Datalist su Opera: stato inizialeFigura 37 - Datalist su Opera: opzioni della datalistFigura 38 - Datalist su Opera: valorizzazione dellopzione
  • 72. Esempi dusoPer utilizzare datalist prima di tutto dobbiamo scrivere un input a cui collegare la nostra datalist.Per collegare linput alla datalist basta impostare lattributo list dellinput con lid della datalist.Per ogni suggerimento che vogliamo dare allutente facciamo discendere da datalist un tag option,mettendo il suggerimento nellattributo value. Il value delloption non deve essere vuoto e loptionnon deve essere settata su disabled per essere visualizzata.Vediamo il codice:<form name="commenti" method="post" action="/141/comments"> [...] <label>Stato danimo: <input type="text" name="mood" placeholder="felice, triste, incuriosito, ..." list="stato-danimo"> <datalist id="stato-danimo"> <option value="triste"> <option value="annoiato"> <option value="curioso"> <option value="felice"> <option value="entusiasta!"> </datalist> </label> [...] <input type="reset" value="Resetta il form"> <input type="submit" value="Invia il commento"></form>Tabella del supporto sui browserForm: nuovi tipi di inputdatalist No 4.0+ No No 9.0+ La potenza dei microdatiIntroduzione: semantica e rich snippetLeggendo questa guida dovrebbe essere chiaro che un punto focale di HTML5 è la semantica.HTML5 ha introdotto infatti diversi tag semantici (come header, article o nav) che permettono distrutturare il contenuto secondo una logica, appunto, semantica. Ma questa suddivisione non assolvea tutte le necessità semantiche di cui il web ha bisogno.Lobbiettivo è quello di dare la possibilità a programmi come crawler dei motori di ricerca o screenreader di comprendere il significato del testo. Queste informazioni sono accessibili da questi
  • 73. programmi e rimangono (attualmente) invisibili per lutente. Entrano qui in gioco i cosiddettimicrodati.Ecco come Google li descrive, allinterno della Guida di Strumenti per i Webmaster: "La specifica dei microdati HTML5 è un modo per assegnare etichette ai contenuti al fine di descrivere un tipo specifico di informazioni (ad esempio recensioni, informazioni su persone o eventi). Ogni tipo di informazione descrive uno specifico tipo di elemento, come una persona, un evento o una recensione. Ad esempio, un evento ha proprietà quali il luogo, lora di inizio, il nome e la categoria."Attualmente, la cosa forse più interessante relativa ai microdati è in effetti uscita fuori dai laboratoridi Google: si tratta dei cosiddetti rich snippet. I rich snippet sono risultati della ricerca di Google incui, oltre alle comuni informazioni, compaiono altri dati allegati, come nelle immagini qui sotto:Figura 39 - Rich snippet relativo a un hotelFigura 40 - Rich snippet con informazioni personaliI microdata in praticaApplicare i microdati è semplice: per ogni tag HTML possiamo specificare degli attributi che cipermettono di definire gli oggetti semantici.Prima di tutto dobbiamo applicare a un elemento radice (cioè un elemento che contiene tutte leinformazioni che vogliamo specificare) itemscope e itemtype.itemscope definisce lelemento a cui è applicato è un contenitore delloggetto che andremo adescrivere.itemtype definisce il vocabolario che specifica il tipo di oggetto che andremo a descrivere.Per finire, sugli elementi che discendono dallelemento radice specifichiamo lattributo itemprop chedefinisce la proprietà che verrà valorizzata con il testo contenuto nel tag.Ecco un esempio semplice:<div itemscope itemtype="http://data-vocabulary.org/Person">My name is <span itemprop="name">Simone Bonati</span> and my nickname is <span itemprop="nickname">svarione</span> on several site (like twitter). Here is my twitter account: <a href="http://www.example.com" itemprop="url">http://twitter.com/svarione</a> I li
  • 74. ve in Milano, Italy and work as <span itemprop="role">web developer</span>.</div>Possiamo anche nidificare gli oggetti. Ecco un esempio:<div itemscope itemtype="http://data-vocabulary.org/Person">My name is <span itemprop="name">Simone Bonati</span> and my nickname is <span itemprop="nickname">svarione</span> on several site (like twitter). Here is my twitter account: <a href="http://www.example.com" itemprop="url">http://twitter.com/svarione</a> I live in <span itemprop="address" itemscope itemtype="http://data-vocabulary.org/Address"> <span itemprop="locality">Milano</span>, <span itemprop="country-name">Italy</span> </span> and work as <span itemprop="role">web developer</span>.</div>I vocabolariPer sfruttare al massimo la potenza dei microdati e per ottenere i rich snippet dobbiamo usare ivocabolari (che specifichiamo, come abbiamo visto, con itemtype) supportati da Google.I vocabolari descrivono linsieme di proprietà che possono essere definite per un determinato oggetto.I vocabolari più popolari supportati da Google sono: Breadcrumbs: questo vocabolario serve a rappresentare un insieme di link che può aiutare un utente a comprendere e navigare allinterno del sito. Businesses and organizations: questo vocabolario definisce una società, un negozio e più in generale un luogo. People: questo vocabolario definisce una persona. Address: questo vocabolario definisce un indirizzo. Events: questo vocabolario definisce un evento (con informazioni come il titolo, la data e il luogo). Product: questo vocabolario definisce un prodotto. Offer: questo vocabolario definisce unofferta. Offer-aggregate: questo vocabolario definisce un aggregato di offerte (con prezzo minimo, prezzo massimo, etc). Recipes: questo vocabolario definisce una ricetta. Review: questo vocabolario definisce una singola recensione. Review-aggregate: questo vocabolario definisce una recensione aggregata. Rating: questo vocabolario definisce una valutazione.Link utiliGoogle: informazioni sui microdati (http://www.google.com/support/webmasters/bin/answer.py?hlrm=en&answer=176035)Vocabolario Breadcumbs (http://data-vocabulary.org/Breadcrumb)
  • 75. Vocabolario Businesses and Organizations (http://data-vocabulary.org/Organization)Vocabolario People (http://data-vocabulary.org/People)Vocabolario Address (http://data-vocabulary.org/Address)Vocabolario Events (http://data-vocabulary.org/Event)Vocabolario Products (http://data-vocabulary.org/Product)Vocabolario Offer (http://data-vocabulary.org/Offer)Vocabolario Aggregate (http://data-vocabulary.org/Offer-aggregate)Vocabolario Recipes (http://data-vocabulary.org/Recipes)Vocabolario Reviews (http://data-vocabulary.org/Review)Vocabolario Review-aggregate (http://data-vocabulary.org/Review-aggregate)Vocabolario Rating (http://data-vocabulary.org/Rating) Nuova linfa alle applicazioni webL’acronimo alla base di HTML è chiaro, ‘HyperText Markup Language’; ipertesto: un insieme didocumenti messi in relazione tra loro da parole chiave. La tecnologia in questione dovrebbe esserequindi utile per strutturare collezioni di contenuti legati fra di loro in modo più o meno oggettivo;Wikipedia ne è il classico e più calzante esempio. Lascia invece un po’ più perplessi realizzare chel’HTML è sempre più la base di vere e proprie applicazioni web: google docs, Google Maps,Meebo, solo per citarne alcune, dove la forma ipertestuale è decisamente marginale quando noncompletamente assente. Come già abbiamo avuto modo di anticipare, l’HTML5 nasce anche permeglio indirizzare questo crescente filone di realtà web, mettendo a disposizione dello sviluppatoreuna nutrita serie di nuovissime API studiate per dare adito alle più ardite applicazioni all’interno di unbrowser. È un po’ come se il prematuro sogno di Marc Andressen(http://www.forbes.com/forbes/1997/1201/6012308a_print.html) stesse per avverarsi.La risposta ad un bisogno molto sentitoLo sforzo profuso prima dal gruppo WHAT e poi dal W3C è stato parzialmente accentuato dallanecessità di porre un freno al dilagare di tecnologie, parallele all’HTML, sorte per rispondere ai nuovibisogni delle applicazioni web. Il motivo principale di questo comportamento è da ricercarsi nellanecessità di mantenere unito il controllo sullo standard e, conseguentemente, di evitare chel’insediamento in pianta stabile di soluzioni non interne al consorzio possa complicare di fatto lagestione dell’intero sistema.Flash ed il cugino Flex sono due ottimi esempi della tendenza intrapresa dal web in tal senso, seguonoGoogle Gears, Google O3D e un’infinita di altre estensioni, ognuna delle quali cerca di riempire unvuoto più o meno piccolo percepito dagli utenti della rete.I punti chiave dell’offerta
  • 76. Ecco un elenco esaustivo delle API trattate nelle prossime lezioni della guida. E` possibile suddivideretale insieme sommariamente in due categorie: nella prima, multimedialità, trovano spazio le APIstudiate per gestire ed incanalare nuovi strumenti di comunicazione, come video, audio e graficabi/tridimensionale; nella seconda, che invece potremmo chiamare arricchimento, si posizionano lenuove funzionalità studiate per avvicinare l’esperienza di fruizione di una web application a quella diun normale programma eseguito in una finestra del desktop.Multimedialità Gestione di flussi video (il tag <video> e le relative API); Gestione di flussi audio (il tag <audio> e le relative API); Gestione di grafica libera bi/tridimensionale (il tag <canvas> e le relative API); Grafica vettoriale e notazioni matematiche (i tag <svg>, <math> e le relative API).Arricchimento Applicazioni web offline (file .manifest e API di sincronizzazione); Memorizzazione di informazioni sul browser (WebSQL e LocalStorage API); Javascript asincrono e parallelo (Web Workers API); Comunicazioni bidirezionali tra client e server (Web Socket API); Drag and Drop; Utilizzo di informazioni georeferenziate (GeoLocation API).Oltre a questo elenco, meritano di essere citate e brevemente esplorate alcune funzionalità che,seppur non rivoluzionarie, promettono di semplificare alcuni aspetti dello sviluppo odierno diapplicazioni web.Manipolare la cronologia: le History APITutti conosciamo il meccanismo per navigare all’interno della cronologia del browser:alert("La cronologia contiene " + history.length + " documenti." );// torna al documento precedentehistory.back();Meno invece sanno che di questo oggetto history, seppur supportato dalla totalità degli user-agent,non esiste traccia nelle attuali specifiche HTML. Con l’avvento della versione 5 il W3C ha decisodiincludere le API per la navigazione della cronologia all’interno del futuro standard; l’occasionesi è rivelata ghiotta anche per un interessante arricchimento delle funzionalità. In particolare è orapossibile creare nuovi elementi della cronologia associando loro un payoff di dati, come ad esempioun hash chiave-valore, che poi potrà essere recuperato attraverso l’utilizzo del tasti di navigazione delbrowser. Vediamone un esempio:<!doctype html><html><head> <title>Messaggi dalla storia:</title> <script> historyInject = function(){ message = prompt(Che messaggio vuoi salvare in history?); history.pushState(message, document.title + " " + message + ""); };
  • 77. onpopstate = function(event){ document.getElementById("messagelist"). insertAdjacentHTML(beforeend,"<li>"+event.state+"</li>"); } </script></head><body> <h1>Lista dei messaggi presenti nella cronologia:</h1> Premi il tasto back del browser o <a href="javascript:historyInject();return false;"> carica un nuovo messaggio.</a> <ul id="messagelist"></ul></body></html>La funzione historyInject crea, attraverso il metodo pushState, un nuovo elemento nellacronologia che contiene il messaggio generato dall’utente. Successivamente, la pressione del tastoback del browser viene intercettata dall’handler onpopstate che recupera il messaggio e lo aggiungeall’elenco a fondo pagina. Con questo meccanismo diviene possibile simulare una normalenavigazione con i pulsanti back e forward anche all’interno di applicazioni web che fanno uso intensivodi Javascript, come ad esempio la maggior parte delle realizzazioni sviluppate con il framework Ext.JS(http://dev.sencha.com/deploy/dev/examples/).Associare protocolli e MIME type alla propria web applicationSupponiamo di aver sviluppato una web application per inviare e ricevere sms. Le specifiche HTML5introducono la possibilità di registrare la propria applicazione come gestore preposto ad uno specificoprotocollo; nel nostro caso sarebbe quindi auspicabile che qualunque link nel formato:<a href="sms://+39396819577">Manda un SMS a Sandro Paganotti</a>convogli l’utente alla nostra applicazione a prescindere dal sito in cui si trova il link, un po’ comesuccede con il client di posta al click di link col protocollo ‘mailto’. Registrare un protocollo è moltosemplice:<!doctype html><html><head> <title>TuttiSMS: Il servizio per inviare e ricevere SMS</title> <script> registraProtocollo = function(){ navigator.registerProtocolHandler( sms, http://localhost/invia_sms?dest=%s, TuttiSMS); };</script></head><body onload="registraProtocollo();"></body></html>
  • 78. Caricando la pagina in un browser che supporta questa funzionalità, noi abbiamo usato Firefox 3.5,verremo notificati della volontà da parte dell’applicazione web di registrare il protocollo sms epotremo decidere se consentire o meno l’operazione:Figura 41 (click per ingrandire) - Associazione del protocollo su Firefox(http://www.html.it/guide/esempi/html5/imgs/lezione_api/1.jpg)Una volta accettata questa associazione, ad ogni link nel formato: ‘sms://qualsiasi_cosa’ seguiràun redirect automatico all’indirizzo specificato come parametro nella funzioneregisterProtocolHandler, nel nostro caso: ‘http://localhost/invia_sms?dest=%s’, con laparticella ‘%s’ sostituita con l’intero link in questione. Ecco un esempio di risultato:http://localhost/invia_sms?dest=sms%3A%2F%2F%2B39396819577E’ possibile seguire esattamente la stessa procedura anche per registrare uno specifico MIME typeutilizzando la funzione gemella: registerContentHandler.Un progetto ambiziosoChiudiamo la lezione gettando le basi per lo sviluppo del progetto guida associato al prossimo gruppodi lezioni: FiveBoard, una lavagna interattiva basata su canvas. Chiaramente l’obiettivo del progettoè quello di fornire un pretesto per poter esplorare le novità introdotte dall’HTML5 in un contesto unpo’ più ampio rispetto a quello solitamente offerto. Proprio per questo alcune scelte potranno essereopinabili in un ottica di efficenza o di strutturazione dell’architettura.Bene, cominciamo creando una cartella di progetto, ‘fiveboard’, contenente un file ‘index.html’ e unacartella ‘js’ con un ulteriore file ‘application.js’:Figura 42 - Vista delle cartelle
  • 79. Ora impostiamo la pagina html perché richiami il file Javascript:<!doctype html><html lang=it><head> <meta charset="utf-8"> <title>FiveBoard: uno spazio per gli appunti.</title> <script src="js/application.js" defer></script></head></html>L’attributo defer, poco supportato perché definito in modo poco chiaro nelle specifiche HTML4(http://www.w3.org/TR/html401/interact/scripts.html#h-18.2.1), assume nella versione 5 unsignificato più delineato: “(se) [..] lattributo defer è presente, allora lo script viene eseguito quando la pagina ha finito di essere processata.”In questo nuovo contesto è interessante l’utilizzo di defer per velocizzare il caricamento della paginaposticipando in seconda battuta il load del file Javascript. Da notare, prima di proseguire, anchel’aggiunta nelle specifiche dell’attributo async che causa il caricamento dello script in parallelo, oasincrono, da qui il nome, rispetto a quello della pagina.Prima di concludere sinceriamoci del funzionamento del nostro impianto aggiungendo al fileJavascript:alert("pronti per cominciare!");e caricando il tutto all’interno di un browser:Figura 43 (click per ingrandire) - Risultato delloperazione
  • 80. (http://www.html.it/guide/esempi/html5/imgs/lezione_api/3.jpg)Codice degli esempiPrima di proseguire, potete scaricare per una migliore consultazione il pacchetto zip(http://www.html.it/guide/esempi/html5/esempi/esempi_html5_api.zip) che contiene il codice di tuttigli esempi che vedremo nelle lezioni che seguono. Applicazioni web offline (file .manifest)Con le Offline API è possibile specificare in un apposito file, detto manifest, un elenco di asset(pagine web, filmati Flash, immagini, fogli di stile CSS, Javascript e quant’altro può finire in unapagina web) dei quali vogliamo che il browser conservi copia locale. Tali oggetti, dopo la primasessione di navigazione online, resteranno quindi accessibili anche in assenza di una connessione direte. In questo modo è possibile creare applicazioni web perfettamente funzionanti ancheoffline. Il primo passo per ottenere questo risultato è aggiungere l’attributo manifest all’elementohtml segnalando così allo user agent l’esistenza di un file preposto alla memorizzazione offline:<!doctype html><html lang=it manifest=fiveboard.manifest>...A questo punto deve essere creato un file con MIME type ‘text/cache-manifest’, dal nomespecificato nel valore dell’attributo, contenente l’elenco dei documenti per i quali si richiede lamemorizzazione offline. Ad esempio, considerando il nostro progetto guida, il file potrebbe risultare:CACHE MANIFESTindex.htmljs/application.js
  • 81. Per fare in modo che il file venga servito con il corretto MIME type ci sono molte soluzioni, tutte,purtroppo, molto legate al tipo di webserver che sostiene la pagina. Nel caso si tratti del popolareApache la soluzione più veloce consiste nel creare un file ‘.htaccess’ nella cartella principale delprogetto contenente la seguente istruzione:AddType text/cache-manifest manifestUna volta soddisfatte queste condizioni è possibile verificare il buon funzionamento delle APIutilizzando un browser come Chromium e caricando la pagina assicurandosi di avere i Developer Toolsattivati (CTRL + SHIFT + J) e posizionati sulla sezione ‘Console’ (figura 1):Figura 1 (click per ingrandire)(http://www.html.it/guide/esempi/html5/imgs/lezione_offline/1.jpg)Aggiornando nuovamente il contenuto della pagina riceveremo conferma della correttamemorizzazione in locale dei documenti specificati nel file manifest, ora disponibili anche perconsultazioni in assenza di rete (figura 2):Figura 2 (click per ingrandire)
  • 82. (http://www.html.it/guide/esempi/html5/imgs/lezione_offline/2.jpg)Andare in profonditàIl file .manifest di cui abbiamo accennato nella sezione precedente, offre una serie di interessantifunzionalità aggiuntive; in primo luogo è possibile indicare al browser percorsi di fallback, dautilizzare nel caso in cui durante la navigazione offline si necessiti di risorse non disponibili:CACHE MANIFESTindex.htmlFALLBACK:news.html offline.htmlIn questo esempio, il tentativo di navigazione verso la pagina ‘news.html’ verrà risolto, in caso dibrowser in stato offline, servendo la pagina ‘offline.html’. In caso fosse necessario convogliare risorsemultiple si può anche far ricorso a wildcard, ad esempio:CACHE MANIFESTindex.htmlFALLBACK:news.html offline.htmlnews/* offline.htmlCosì facendo anche la navigazione verso una pagina di dettaglio news, come ad esempio ‘news/10/12/2010/nuovi-progressi-al-cern’ verrà servita in assenza di rete con il contenuto di ‘offline.html’.Usando la sezione ‘NETWORK’ è invece possibile notificare risorse che devono sempre essererecuperate online:CACHE MANIFESTindex.htmlNETWORK:saldo_conto_corrente.php
  • 83. Le API associateLa gestione della cache introduce tutta una serie di eventi e proprietà che consentono di acquistarecontrollo su ogni passo della procedura, vediamoli in questo esempio (offline.html), che stampa avideo un nuovo elemento di un elenco puntato per ogni evento intercettato:<!doctype html><html lang=it manifest=offline.manifest><head> <title>Tutti i passi della cache</title> <script> // Funzione di servizio: say = function(message){ document.getElementById("cache-steps"). insertAdjacentHTML(beforeend,"<li>"+message+";</li>"); } clear = function(message){ document.getElementById("cache-steps").innerHTML = ""; } // Loggetto che controlla la cache var appCache = window.applicationCache; // Nuovi eventi disponbili con le Offline API appCache.addEventListener(checking, function(ev) { say("Controllo, se posso, che il .manifest online non sia cambiato"); }, false); appCache.addEventListener(noupdate, function(ev) { say("Il .manifest non è cambiato"); }, false); appCache.addEventListener(downloading, function(ev) { say("Inizio a scaricare i file listati dal manifest che non ho già in cache"); }, false); appCache.addEventListener(progress, function(ev) { say("Scarico una risorsa"); }, false); appCache.addEventListener(cached, function(ev) { say("Tutte le risorse sono state scaricate"); }, false); appCache.addEventListener(updateready, function(ev) { say("Ho scaricato una nuova versione della cache e sono pronto "+ "a sostituirla alla precedente"); }, false); appCache.addEventListener(obsolete, function(ev) {
  • 84. say("Ho cercato il .manifest online ottenendo un 404 o 410 come risposta " + "probabilmente il sito non supporta più funzionalità di " + "caching, cancello la cache in locale."); }, false); appCache.addEventListener(error, function(ev) { say("Ops, si è verificato un errore"); }, false); </script></head><body> <button onclick="clear();appCache.update();">Forza il controllo della cache</button> <ul id="cache-steps"> </ul></body></html>Proviamo ad eseguire questa pagina in Chromium senza aver preventivamente creato il file‘offline.manifest’ (figura 3):Figura 3Creiamo ora un semplice ‘offline.manifest’ come segue,CACHE MANIFESToffline.htmle ricarichiamo la pagina (figura 4):Figura 4
  • 85. Ricarichiamo nuovamente la pagina per certificare l’avvenuto cache delle risorse (figura 5):Figura 5Bene, da qui si dipanano tutta una serie di comportamenti interessanti come ad esempio: modificareil file .manifest e forzare il controllo della cache, oppure rimuovere il file .manifest e ricaricare lapagina. Provando ognuno di essi con lo script che abbiamo appena steso sarà facile identificare i varieventi coinvolti. Ecco la demo(http://www.html.it/guide/esempi/html5/esempi/lezione_offline/offline.html).ConclusioniCome avete potuto notare le attività per far in modo che il nostro progetto guida benefici delle OfflineAPI sono state semplici e di pochissimo impatto sull’architettura della pagina. E` importante peròricordare che man mano andremo ad aggiungere risorse al progetto (immagini, librerie, etc...) sarànecessario includerle nel file .manifest pena il malfunzionamento dello stesso in assenza diconnessione.Tabella del supporto sui browser
  • 86. API e Web ApplicationsApplicazioni web offline (.manifest) No 3.5+ 4.0+ 2.0+ 10.6+ Indexed Database APIQueste API nascono per dare la possibilità di creare e manipolare un database di ispirazione NoSQLmemorizzato allinterno del browser dellutente. Ogni database, identificato da un nome, puòcontenere un numero arbitrario di Object Store, letteralmente contenitori di oggetti: ad esempio unipotetico database ‘libreria potrebbe ospitare i seguenti Object Store: Libri, Clienti. Sia ‘Libri che‘Clienti non sono altro che strutture paragonabili ad array associativi ordinati, dove ogni coppiachiave-valore rappresenta un oggetto, quindi in questo caso o un libro o un cliente.Allinterno di un Object Store è possibile eseguire le normali operazioni di inserimento, modifica,eliminazione e ricerca; le API sono state pensate per ragionare con record in un formato JSON-likema nulla vieta di memorizzare oggetti Javascript di fattura diversa, purché serializzabili.Come funzionano le APIUtilizziamo Chromium per un tour operativo di questo interessante set di API; iniziamo preparando undocumento HTML5 e creando il database:<!doctype html><html><head> <title> WebLibreria: gestionale per librerie </title> <script> setup = function(){ if (webkitIndexedDB in window){ indexedDB = webkitIndexedDB; IDBCursor = webkitIDBCursor; IDBKeyRange = webkitIDBKeyRange; IDBTransaction = webkitIDBTransaction; }else if (moz_indexedDB in window){ indexedDB = moz_indexedDB; } } init = function(){ setup(); var request = indexedDB.open("WebLibreria", "Il gestionale per librerie"); } </script></head><body onload="init();"></body></html>
  • 87. Essendo, ad oggi, queste features ancora sperimentali Chromium (e Firefox) prefissano le classi diriferimento con la particella ‘webkit: la funzione ‘setup serve solamente per creare degli alias cheabbiano nomi più aderenti alle specifiche. Mano a mano che queste API si avvicineranno allo status distandard assisteremo alla rimozione di questi prefissi e potremo commentare la funzione setup. Lacreazione del database avviene attraverso listruzione ‘indexedDB.open, che accetta come parametroil nome e la descrizione delloggetto che stiamo creando; in caso un database con lo stesso nome e lostesso dominio di origine sia già presente nel browser allora verrà utilizzato questultimo.A questo punto possiamo intercettare gli eventi di avvenuta creazione della connessione e di erroredurante la procedura gestendoli nel modo che meglio ci aggrada:init = function(){ setup(); var request = indexedDB.open("WebLibreria", "Il gestionale per librerie"); request.onsuccess = function(){console.log("Connessione Ok!");} request.onerror = function(){console.log("Ops, errore");}}Eseguiamo la pagina allinterno di Chromium prestando attenzione alla linguetta console allinternodei Developer Tools (CTRL + SHIFT + J) e avremo conferma dellavvenuta connessione/creazione aldatabase (figura 1):Figura 1 (click per ingrandire)(http://www.html.it/guide/esempi/html5/imgs/lezione_database/1.jpg)Ora che abbiamo stabilito una connessione è essenziale determinare se lutente sia alla sua primavisita, perché in questo caso è necessario procedere con la creazione degli object store e dellastruttura necessari. Per gestire questo meccanismo le API mettono a disposizione il concetto diversione, impostata a null per un database appena creato, che può essere utilizzata proprio capirequando sia necessario apportare modifiche alla struttura. Ad esempio:...init = function(){ setup(); var request = indexedDB.open("WebLibreria", "Il gestionale per librerie"); request.onsuccess = controllaVersione; request.onerror = function(){console.log("Ops, errore");} }controllaVersione = function(event){ window.database = event.result;
  • 88. if(database.version != "1.0"){ var request = database.setVersion("1.0"); request.onsuccess = aggiornaLoSchema; request.onerror = function(){console.log("Ops, errore");} }else{ // il database è già aggiornato alla versione più recente }}aggiornaLoSchema = function(){console.log("Qui posso aggiornare lo schema");}...La funzione aggiornaLoSchema viene invocata solamente nel caso in cui la versione del database sulbrowser dellutente sia diversa da quella attesa dal javascript (in questo caso la ‘1.0); in particolareregistrare una funzione sul callback ‘onsuccess del metodo setVersion è lunico modo in cui siaconsentito dalle specifiche modificare la struttura del database.Se ora provate questo codice allinterno del browser, nella linguetta console vedrete comparire lascritta ‘Qui posso aggiornare lo schema, se poi ricaricate nuovamente la pagina invece noterete chetale messaggio scompare: il database è infatti già nella versione “1.0”, quindi il flusso del programmatransita attraverso il blocco else, che è al momento vuoto. Per cancellare il database creato e potercosì ripetere la procedura è necessario svuotare completamente la cache, chiudere Chromium eriaprirlo (figura 2):Figura 2 (click per ingrandire)(http://www.html.it/guide/esempi/html5/imgs/lezione_database/2.jpg)A questo punto creiamo la struttura del database: per prima cosa dobbiamo aprire una transazione,successivamente istruiamo il database alla creazione dellobject store ‘libri, con chiave sul campo‘isbn, e di due indici, rispettivamente per i campi ‘titolo e ‘autore. Approfittiamone anche per crearela funzione recuperaLibri, che verrà invocata sia al completamento della struttura sia nel caso ildatabase sia già alla versione desiderata:...controllaVersione = function(event){ window.database = event.result; if(database.version != "1.0"){ var request = database.setVersion("1.0"); request.onsuccess = aggiornaLoSchema; request.onerror = function(){console.log("Ops, errore");}
  • 89. }else{ recuperaLibri(); }}aggiornaLoSchema = function(){ window.transazione = event.result; transazione.oncomplete = recuperaLibri; transazione.onabort = function(){console.log("Ops, errore");} var libri = database.createObjectStore("libri", "isbn", false); var titolo = libri.createIndex("titolo", "titolo", false); var autore = libri.createIndex("autore", "autore", false);}recuperaLibri = function(){ // recupera lelenco dei libri e stampali a video}...La funzione createObjectStore richiede 3 parametri, di cui solamente il primo, il nome, obbligatorio;il secondo parametro rappresenta il nome della proprietà del record che vogliamo funga da chiaveallinterno dellobject store. Il terzo parametro imposta invece la proprietà autoincrement; nel casonon sia presente una chiave nel record in inserimento e autoincrement = true, una chiave verràgenerata in automatico. Le due chiamate alla funzione createIndex provvedono alla creazione di dueindici, utili per ricerche e query, sui campi ‘titolo e ‘autore; il terzo parametro impostato afalseconsente la presenza di valori duplicati. Ora che abbiamo creato la struttura del databasestampiamo a video lelenco, per ora vuoto, dei libri registrati e creiamo un piccola form perlinserimento di un nuovo volume:...recuperaLibri = function(){ window.transazione = database.transaction(["libri"], IDBTransaction.READ_WRITE, 0); var request = transazione.objectStore("libri").openCursor(); request.onsuccess = stampaLibri; request.onerror = function(){console.log("Ops, errore");}}stampaLibri = function(){ var cursor = event.result; if( cursor != null){ document.getElementById("catalogo_libri").insertAdjacentHTML(beforeend, "<li>" + cursor.value.autore + ": " + cursor.value.titolo + " (ISBN: "+ cursor.value.isbn +"); </li>"); cursor.continue(); }}aggiungiLibro = function(){// aggiungiamo un nuovo libro allobject store}</script></head><body onload="init();"> <h1> WebLibreria: gestionale per librerie</h1>
  • 90. <section> <h1>Elenco dei libri</h1> <ul id="catalogo_libri"> </ul> </section> <aside> <h1>Aggiungi un nuovo libro</h1> <form name="aggiungi_libro" onsubmit="aggiungiLibro(this); return false;"> <fieldset name="info_libro"> <legend>Dati richiesti:</legend> <label>Titolo: <input name="titolo" type="text" required placeholder="es: Dalla terra allaluna"> </label> <label>Autore: <input name="autore" type="text" required placeholder="es: Jules Verne"> </label> <label>ISBN: <input name="isbn" type="text" required placeholder="es: 8862221320"> </label> <input type="submit" value="Aggiungi"> </fieldset> </form> </aside></body></html>Possiamo tranquillamente tralasciare la spiegazione della nuova porzione di codice HTML aggiunto:trattasi semplicemente di un form che allinvio chiama una funzione, ancora da sviluppare, perlaggiunta di un nuovo libro. Molto più interessanti sono invece recuperaLibri e stampaLibri. InrecuperaLibri viene creata una nuova transazione che coinvolge lobject store ‘libri; il secondoparametro indica il tipo di transazione: purtroppo lettura/scrittura (IDBTransaction.READ_WRITE) èlunica opzione supportata ad oggi; il terzo valore rappresenta invece il timeout della transazione: lo 0utilizzato significa mai. Vediamo listruzione successiva:var request = transazione.objectStore("libri").openCursor();La funzione openCursor inizializza un puntatore, detto anche cursore, al primo record dellobjectstore ‘libri. La funzione stampaLibri, che viene chiamata appena il cursore è stato creato e popolauna lista con i libri in catalogo, agisce come una specie di ciclo, infatti il metodo continue non fanientaltro che richiamare nuovamente stampaLibri, posizionando però il cursore al record successivo;questo fino a quando non si giunge alla fine dei risultati di ricerca, a quel punto il valore del cursorediviene null e un apposito if si preoccupa dellabbandono della funzione.Completiamo il nostro progetto con la funzione aggiungiLibro:...aggiungiLibro = function(data){ var elements = data.elements window.transazione = database.transaction(["libri"], IDBTransaction.READ_WRITE, 0);
  • 91. var request = transazione.objectStore("libri").put({ titolo: elements[titolo].value, autore: elements[autore].value, isbn: elements[ isbn].value }, elements[ isbn].value)); request.onsuccess = function(){pulisciLista(); recuperaLibri();} request.onerror = function(){console.log("Ops, errore");}}pulisciLista = function(){ document.getElementById("catalogo_libri").innerHTML ="";}</script>Il metodo interessante in questo caso è il put, che si preoccupa di aggiungere al database, previaapertura di una transazione appropriata, un nuovo record con gli elementi ricevuti dal form (da notareil secondo parametro, corrispondente alla chiave del record). Da notare che esiste anche un metodoadd che differisce nellimpedire la creazione di un record la cui chiave sia già presente nel database.Eseguiamo un ultima volta lapplicazione, proviamo ad inserire un paio di libri ed ammiriamone ilrisultato (figura 3):Figura 3 (click per ingrandire)(http://www.html.it/guide/esempi/html5/imgs/lezione_database/3.jpg)Una funzione di ricercaAggiungiamo questa funzione al progetto:...ricercaLibro = function(autore){ pulisciLista(); window.transazione = database.transaction(["libri"], IDBTransaction.READ_WRITE, 0); var request = transazione.objectStore("libri").index(autore).openCursor(
  • 92. IDBKeyRange.bound(autore,autore+"z",true,true), IDBCursor.NEXT); request.onsuccess = stampaLibri; request.onerror = function(){console.log("Ops, errore");}}</script>Lunica differenza rispetto alla già analizzata recuperaLibri sta nel fatto che, in questo caso, con ilmetodo ‘index(‘autore) indichiamo al database che la selezione dovrà essere fatta utilizzandocome discriminante lindice ‘autore creato sullomonimo campo. In particolare tale selezione dovràrecuperare tutti i record il cui autore inizia con una stringa passata al metodo. Per provare questafunzione di ricerca creiamo un nuovo frammento HTML in coda alla form di inserimento:... </form> <h1>Cerca un libro per autore</h1> <form name="cerca_per_autore" onsubmit="ricercaLibro(this.elements[keyword].value); return false;"> <fieldset name="campi_ricerca"> <legend>Ricerca per autore:</legend> <label>Inizio del nome: <input name="keyword" type="search" required placeholder="es: Franc"> </label> <input type="submit" value="Ricerca"> </fieldset> </form></aside>...Ricarichiamo lapplicazione e proviamo ad inserire una valida stringa di ricerca (figura 4):Figura 4 (click per ingrandire)
  • 93. (http://www.html.it/guide/esempi/html5/imgs/lezione_database/4.jpg)ConclusioneLe Indexed Database API sono uno strumento estremamente potente che consentono di beneficiare diun vero e proprio database allinterno del browser dellutente. Le stesse funzionalità, anche se in unasintassi più orientata a SQL, venivano offerte anche dalle promettenti Web SQL Database API(http://www.w3.org/TR/webdatabase/), abbandonate dal 4 dicembre 2010 per motivi di sicurezza edi, ironia della sorte, troppa uniformità di implementazione da parte degli user-agent (avevano tuttiscelto SQLlite come back-end per questo tipo di specifiche).Prima di passare alla prossima lezione ricordo che le stesse API che abbiamo usato in forma asincronaallinterno di questo progetto sono disponibili anche nel formato sincrono; per maggiori informazioniin questo senso rimando alla documentazione ufficiale (http://www.w3.org/TR/IndexedDB/).Per testare il tutto potete partire dalla demo(http://www.html.it/guide/esempi/html5/esempi/lezione_indexeddb/indexeddb.html).Tabella del supporto sui browserAPI e Web ApplicationsIndexed Database API 9.0+ (parziale) 4.0+ (parziale) 5.0+ (parziale) 8.0+ (parziale) No WebStorage API
  • 94. Le WebStorage API nascono per risolvere due problematiche tipiche dei cookies; la loro limitatadimensione massima (tipicamente 4K) e l’impossibilità di avere cookies differenziati tra duediverse sessioni di navigazione sullo stesso dominio dallo stesso browser. Il secondo punto siesplicita molto bene cercando di mantenere aperti contemporaneamente due account Gmail sullostesso browser, ogni navigazione sul primo comporterà il logout del secondo e viceversa.I problemi in questione sono stati risolti creando due nuovi oggetti. sessionStorage consente diavere un meccanismo di persistenza dei dati distinto per ogni sessione di navigazione in ogni finestra,o tab, del browser. Usando sessionStorage sarebbe quindi possibile coordinare l’aperturacontemporanea di due distinti account GMail sullo stesso browser. localStorage mantiene ilcomportamento del cookie essendo comune a tutte finestre del browser che condividono lo stessodominio. Entrambi sono inoltre stati studiati per ospitare molti più dati, almeno 5Mb, ed esserepersistenti anche alla chiusura ed alla riapertura del browser.Le specificheLe API si compongono di una singola interfaccia Storage. localStorage e sessionStorageimplementano entrambi questa interfaccia e quindi dispongono dello stesso set di metodi anche sechiaramente restano due oggetti distinti. Le principali operazioni possono essere eseguite come su diun normale array associativo:localStorage.nome = Sandro;localStorage.cognome = Paganotti;o con l’ausilio di metodi dedicati:localStorage.setItem(nome,Sandro);localStorage.getItem(nome); // ritorna SandroSe però ci accingiamo ad inserire valori diversi da stringhe il comportamento diverge: in un oggettocome localStorage o sessionStorage è consentita la memorizzazione di soli contenuti testuali:localStorage.ordini = Array("1","2","3");localStorage.ordini; // ritorna "1,2,3"È quindi necessario ricorrere a stratagemmi, come la serializzazione su JSON, per ottenere l’effettodesiderato:localStorage.ordini = JSON.stringify(Array(1,2,3));JSON.parse(localStorage.ordini); // ritorna un array di 3 elementi: [1,2,3]Chromium mette a disposizione degli sviluppatori web che intendono utilizzare queste API la linguetta‘Storage’ dei Developer Tools (raggiungibili da menu o con la combinazione di tasti Control - Shift -J e visibile in figura 1):Figura 1 (click per ingrandire)
  • 95. (http://www.html.it/guide/esempi/html5/imgs/lezione_webstorage/1.jpg)Un esempioUtilizziamo il progetto guida per implementare una meccanica di salvataggio dei dati basata sulocalStorage. Non avendo ancora sviluppato la gestione della lavagna ci concentreremo sulmemorizzare e visualizzare stringhe inserite dall’utente attraverso una textarea, iniziamo con ilmarkup completando il file index.html:<!doctype html><html lang=it manifest=fiveboard.manifest><head> <meta charset="utf-8"> <title>FiveBoard: uno spazio per gli appunti.</title> <script src="js/application.js" defer></script></head><body> <hgroup> <h1>Dì qualcosa </h1> <h2>FiveBoard ricorda tutto</h2> </hgroup> <form name="form_da_ricordare"> <menu type="toolbar"> <button type="button" onclick="salvaIlDato(this.form.elements[testo_da_ricordare].value);"> Memorizza quanto scritto </button> <button type="button" onclick="recuperaIlDato(this.form.elements[testo_da_ricordare]);"> Recupera lultimo testo memorizzato </button> </menu> <label>Cosa hai in mente? <textarea name="testo_da_ricordare" required autofocus placeholder="La lista della spesa, il teatro di questa sera ..."></textarea> </label> </form></body></html>
  • 96. Dato che questo progetto si configura più come una web application che come un sito web,implementiamo una classica struttura di controllo desktop-oriented: la toolbar. All’interno di questa,due semplici pulsanti gestiscono le azioni di memorizzazione e recupero del testo salvato attraversouna textarea; l’attributo ‘autofocus’ indica allo user-agent di portare il cursore in posizione diinserimento testo nell’istante di completo caricamento della pagina.Ora, nel file application.js completiamo l’esempio introducendo le funzioni di salvataggio e di recuperoinformazioni basate su localStorage:salvaIlDato = function(info_da_salvare){ localStorage.ultimo_pensiero = info_da_salvare; alert("Memorizzazione effettuata");};recuperaIlDato = function(elemento){ if(confirm("Sostituire il contenuto attuale con lultimo pensiero memorizzato?")){ elemento.value = localStorage.ultimo_pensiero; }};Bene, non ci resta che provare l’esempio(http://www.html.it/guide/esempi/html5/esempi/lezione_webstorage/fiveboard/index.html)all’interno di Chromium e constatare il suo semplice ma efficace funzionamento, capace di persisterel’informazione anche a seguito di un riavvio del browser.Tabella del supporto sui browserAPI e Web ApplicationsWebStorage 8.0+ 3.6+ 3.1+ 2.0+ 10.5+ Web Workers APII Web Workers nascono per consentire l’esecuzione di porzioni di codice Javascript in modoasincrono, senza intaccare le performance della pagina web in visualizzazione. I Web Workers,nient’altro che file Javascript, possono essere comparati a dei thread che la pagina web può lanciare econ i quali può dialogare attraverso semplici metodi. Ogni WebWorker può eseguire a sua volta altriWebWorkers ed ognuno di essi può effettuare operazioni di I/O, calcoli complessi e quant’altro.Le API in questione prevedono che un WebWorker possa essere generato come oggetto della classeWorker o SharedWorker: nel primo caso la sua esecuzione sarà limitata alla specifica sessione dinavigazione all’interno della finestra (o tab) del browser che l’ha invocato; nel secondo inveceogni sessione di navigazione che condivide la stessa origine (lo stesso dominio) potràconnettersi e scambiare messaggi con il medesimo worker. In questo modo lo SharedWorker
  • 97. assume il ruolo di coordinatore, ottimo per, ad esempio, propagare su tutte le finestre del browserpuntate su di un particolare dominio un messaggio ricevuto dal server.Le specifichePer creare un Worker l’istruzione da eseguire è decisamente semplice:// pagina principalebot_noioso = new Worker(bot_noioso.js);Lo script invocato, ‘bot_noioso.js’, verrà eseguito in asincrono e potrà inviare messaggi verso lapagina principale attraverso la funzione postMessage:// bot_noioso.jspostMessage(Perch´ la terra è tonda?);Per ricevere questi messaggi è necessario registrare una funzione all’handler ‘onmessage’ del workercontenuto nella variabile bot_noioso: chiaramente utilizzando la stessa variabile è possibile inviare,sempre tramite postMessage messaggi al worker.// pagina principalebot_noioso = new Worker(bot_noioso.js);bot_noioso.onmessage = function(event){ bot_noioso.postMessage(prompt(event.data));}Allo stesso modo è possibile registrare l’handler ‘onmessage’ anche all’interno del file del worker:// bot_noioso.jspostMessage(Perch´ la terra è tonda?);onmessage = function(event){ if(event.data != null){ postMessage(Perch´: + event.data + ?); }}Ora, se lanciamo Chromium potremo sincerarci del buon funzionamento dello script (figura 1):Figura 1 - Testo
  • 98. Le API dello SharedWorker differiscono in modo sensibile rispetto a queste, anche se ovviamentemantengono immutato il funzionamento di base; per poterle trattare con la dovuta cura costruiamoun piccolo esempio che le utilizzi.Ecco la demo(http://www.html.it/guide/esempi/html5/esempi/lezione_webworkers/webworker.html).Un esempioContinuiamo con il progetto guida; l’obiettivo di questo capitolo è beneficiare delle feature di unoSharedWorker per implementare una dashboard di controllo, che amministri le sessioni diFiveboard aperte contemporaneamente in un browser. Per raggiungere questo (ambizioso) bersagliocreeremo un file ‘js/hub.js’, presso il quale tutte le finestre attive del progetto dovranno registrarsi,che convoglierà le informazioni da e verso una console ‘dashboard.html’. Ecco uno schemadell’architettura (figura 2):Figura 2 (click per ingrandire)
  • 99. (http://www.html.it/guide/esempi/html5/imgs/lezione_webworkers/2.jpg)Le comunicazioni da e verso lo SharedWorker transitano attraverso oggetti chiamati MessagePort,nell’immagine qui sopra sono esplicitate 4 MessagePort. Una MessagePort è utilizzata implicitamenteanche dall’oggetto Worker del capitolo precedente e quindi non ci si deve sorprendere nell’apprendereche il meccanismo di funzionamento di uno SharedWorker è esattamente lo stesso, fatto salvo che inquesto caso è necessario specificare la porta attraverso la quale si vuole inviare o ricevere ilmessaggio.// Invio di un messaggio ad uno SharedWorkerworker.port.postMessage(...);// Ricezione di un messaggio da uno SharedWorkerworker.port.onmessage = function(evento){ ... }// Dall’interno di uno SharedWorker: invio di un messaggiomessageport_del_destinatario.postMessage(...);// Dall’interno di uno SharedWorker: ricezione di un messaggiomessageport_del_mittente.onmessage = function(event){ ... }Bene, ecco in breve come dovranno comportarsi i 3 componenti che andremo a definire: Index.html Connettersi allo SharedWorker; Presentarsi come Client e specificare il proprio nome (il titolo del documento); Dashboard.html Connettersi allo SharedWorker; Presentarsi come dashboard e ricevere informazioni su tutti i Client già registrati; Essere notificata ad ogni nuova registrazione di un Client;
  • 100. Mantenere a video un elenco dei Client registrati; Hub.js (SharedWorker) Registrare ogni Client e notificare, se presente, la dashboard; Registrare la dashboard ed inviarle tutti i Client registrati fino a quel momento.Lo scambio di messaggi tra le varie parti avverrà tramite stringhe di testo nel formato“chiave:valore”, come ad esempio “registra_client:Documento di prova”; questa scelta non èdettata dalle specifiche, che sono abbastanza lasche in tal senso, ma da una semplice convenzioneadottata anche da alcuni esempi del W3C (http://www.whatwg.org/specs/web-apps/current-work/complete/workers.html#shared-state-using-a-shared-worker).Bene, possiamo partire; iniziamo dal file ‘application.js’ che dovrà assumere questo aspetto:salvaIlDato = function(info_da_salvare){ localStorage.setItem("fb_" + titolo_fiveboard,info_da_salvare); alert("Memorizzazione effettuata");};recuperaIlDato = function(elemento){ if(confirm("Sostituire il contenuto attuale con lultimo pensiero memorizzato?")){ elemento.value = localStorage.getItem("fb_" + titolo_fiveboard); }};var titolo_fiveboard = null;window.onload = function(){ var worker = new SharedWorker(js/hub.js); worker.port.onmessage = function(evento){ nome_comando = evento.data.split(":")[0] valore_comando = evento.data.substr(nome_comando.length + 1); console.log("Ricevuto comando: " + nome_comando); switch (nome_comando){ case pronto: titolo_fiveboard = prompt("Seleziona il titolo per questa FiveBoard"); document.title = "FB: " + titolo_fiveboard; worker.port.postMessage("registra_client:" + titolo_fiveboard); break; } }}Al caricamento della pagina viene attivata la funzione collegata a window.onload: questa crea ilcollegamento con lo SharedWorker (se il worker non è già presente verrà caricato in memoria elanciato) e definisce una funzione di ‘ascolto’ nella quale, per ogni messaggio ricevuto, esegueparticolari azioni a seconda della chiave estratta. In questo momento la funzione reagisce alla solachiave ‘pronto’ chiedendo all’utente un titolo del documento ed inviando il risultato al worker con lachiave ‘registra_client’.Il titolo del documento viene anche utilizzato nelle funzioni di salvataggio e di recupero del dato, perdifferenziare fra di loro le variabili memorizzate su LocalStorage in modo da evitare collisioni durantel’apertura contemporanea di più index.html.Ora definiamo hub.js:
  • 101. var fiveboards_registrate = new Array();var dashboard = null;processa_il_messaggio = function(evento){ nome_comando = evento.data.split(":")[0] valore_comando = evento.data.substr(nome_comando.length + 1); switch (nome_comando){ case registra_client: fiveboards_registrate[valore_comando]=evento.target; if(dashboard != null){ dashboard.postMessage("nuova_fiveboard:" + valore_comando); } break; case registra_dashboard: dashboard = evento.target; for(fiveboard in fiveboards_registrate){ evento.target.postMessage("nuova_fiveboard:" + fiveboard); }break; }}onconnect = function(nuova_finestra){ var port = nuova_finestra.ports[0]; port.onmessage = processa_il_messaggio; port.postMessage("pronto");}L’handler onconnect viene invocato ogni qualvolta una pagina tenta di aprire una connessione verso ilworker; nella funzione si delega al metodo ‘processa_il_messaggio’ la gestione dei futuri scambi train worker e la pagina; a quest’ultima è inoltre segnalato il concludersi delle operazioni con unmessaggio ‘pronto’.La funzione processa_il_messaggio interpreta e gestisce le due chiavi registra_client eregistra_dashboard: nel primo caso aggiunge la MessagePort di comunicazione con il client ad unacollezione fiveboards_registrate e comunica alla dashboard, se presente, la nuova aggiuntatramite un messaggio con chiave nuova_fiveboard. Nel secondo caso registra la MessagePort delladashboard (attraversoevento.target, che corrisponde ad evento.ports[0]) e comunica alla stessatutti client finora memorizzati attraverso un ciclo sulla collezione fiveboards_registrate e ad unmessaggio con la già nota chiave nuova_fiveboard.Perfetto, ora non ci resta che definire markup e Javascript di ‘dashboard.html’:<html lang=it><head> <meta charset="utf-8"> <title>Five(Dash)Board: tutto sotto controllo!.</title> <script> var worker = null; getInfo = function(title){ // to be defined...
  • 102. } init = function(){ worker = new SharedWorker(js/hub.js); worker.port.onmessage = function(evento){ nome_comando = evento.data.split(":")[0] valore_comando = evento.data.substr(nome_comando.length + 1); console.log("Ricevuto comando: " + nome_comando); switch (nome_comando){ case pronto: worker.port.postMessage("registra_dashboard") break; case nuova_fiveboard: document.getElementById("elenco_fiveboard").insertAdjacentHTML(beforeend, "<li>" + "Titolo: " + valore_comando + " " + "(<a href=javascript:getInfo("" + valore_comando +"");>" + "più informazioni" + "</a>)" + "</li>"); break; } } } </script></head><body onload="init();"> <h1>FiveBoard:</h1> <ol id="elenco_fiveboard"> </ol></body></html>Il listato è largamente autoesplicativo sulla base di quanto già enunciato: in questo caso le chiavigestite sono ‘pronto’ e ‘nuova_fiveboard’: mentre la prima attiva il meccanismo di registrazione(registra_dashboard) appena visto in hub.js, la seconda si incarica di popolare una lista ordinataogniqualvolta la pagina riceve una notifica di registrazione di una nuova fiveboard.Eseguiamo il tutto in Chromium e godiamoci il risultato dei nostri sforzi (figura 3):Figura 3 (click per ingrandire)
  • 103. (http://www.html.it/guide/esempi/html5/imgs/lezione_webworkers/3.jpg)È possibile verificare il tutto in questa demo(http://www.html.it/guide/esempi/html5/esempi/lezione_webworkers/fiveboard/index.html).Più informazioni per i più ardimentosiVi siete chiesti a cosa debba servire il link ‘più informazioni’ e la funzione getInfo ad esso collegata?L’idea è questa: al click sul comando il sistema deve mostrare all’utente il testo inserito ed il testomemorizzato per l’istanza selezionata. Per raggiungere l’obiettivo ecco come interverremo: 1. La dashboard chiede allo SharedWorker maggiori_informazioni per una data finestra; 2. Lo SharedWorker mette in diretta comunicazione la finestra in oggetto e la dashboard; 3. La finestra in oggetto comunica alla dashboard testo inserito e testo memorizzato.Ecco uno schema delle comunicazioni (figura 4):Figura 4 (click per ingrandire)(http://www.html.it/guide/esempi/html5/imgs/lezione_webworkers/4.jpg)Il punto 2 è decisamente il più interessante e si avvale di MessageChannel: trattasi di unsemplicissimo oggetto, nato all’interno delle API di comunicazione HTML5(http://www.w3.org/TR/html5/comms.html), contenente due MessagePort ed istruito per fare inmodo che ogni messaggio in ingresso alla porta1 venga recapitato alla porta2 e viceversa.Tutto quello che hub.js deve fare è quindi creare un MessageChannel e dare i due capi del filo (le dueMessagePort) rispettivamente alla dashboard ed al client interessato; per fare questo risulta moltocomodo il secondo argomento del metodo postMessage, che consente appunto di specificare un arraydi porte da allegare ad un messaggio.Tutto chiaro? No? Vediamo le modifiche apportate al progetto:// file dashboard.html
  • 104. // invio della richiesta allo SharedWorker (punto 1) getInfo = function(title){ worker.port.postMessage("maggiori_informazioni:" + title); } // una nuova chiave da gestire. case attendi_testo: evento.ports[0].onmessage = function(e){ alert(e.data); } break;// file hub.js // una nuova chiave da gestire, creazione del canale ed invio delle porte di // comunicazione alla dashboard ed al client interessato (punto 2) case maggiori_informazioni: var channel = new MessageChannel(); dashboard.postMessage("attendi_testo",[channel.port1]); fiveboards_registrate[valore_comando].postMessage("richiedi_testo", [channel.port2]); break;// file application.js // una nuova chiave da gestire, invio delle informazioni richieste attraverso la // MessagePort ricevuta dall’evento (non la MessagePort di comunicazione col worker) // (punto 3) case richiedi_testo: evento.ports[0].postMessage( "testo corrente:" + document.forms[form_da_ricordare].elements [testo_da_ricordare].value + "n" + "testo memorizzato:" + localStorage.getItem("fb_" + titolo_fiveboard) ); break;Eseguiamo il tutto in Chromium ed ammiriamone il risultato (figura 5):Figura 5 (click per ingrandire)
  • 105. (http://www.html.it/guide/esempi/html5/imgs/lezione_webworkers/5.jpg)ConclusioniI Web Worker sono il classico esempio di API semplici solo in apparenza; più ci si addentra in utilizziconcreti più si scoprono possibilità e nuove metodologie di sviluppo. È importante ricordare infatti chesono previsti meccanismi di interazione tra i Web Workers, l’ApplicationCache, e i WebSocket, e cheogni WebWorker può invocarne altri.Sono diretta conseguenza di questa intrinseca flessibilità delle API gli innumerevoli scenari di utilizzoipotizzabili oltre a quello già mostrato, come ad esempio svolgere calcoli complessi (ogni Worker puògirare su di un core differente) quali rendering o image detection in tempo reale, centralizzare lecomunicazioni con il server attraverso uno SharedWorker e un WebSocket oppure monitorare processibrowser-side.Tabella del supporto sui browserAPI e Web ApplicationsWebWorkers No 3.6+ 4.0+ 2.0+ 10.6+ WebSockets APILe WebSockets API introducono, nella loro estrema semplicità, una funzionalità tra le più attese ed
  • 106. emulate: la possibilità di stabilire e mantenere una connessione dati tra browser e serverremotosulla quale far transitare messaggi in entrambe le direzioni. Le attuali specifiche, che lascianoben poco spazio per implementazioni del genere, hanno, nel corso degli anni, dato luogo aworkaround più o meno esotici tra i quali lutilizzo di socket in Flash pilotati via Javascript e dellafamosa tecnica di long polling (lutilizzo continuo di chiamate AJAX mantenute aperte fino allaricezione del dato o al tempo di timeout). Le nuove API offrono invece un meccanismo ben piùsemplice grazie alloggetto WebSocket, al metodo send e allevento onmessage.Prima di passare alla visione delle specifiche e al dovuto esempio di implementazione è importantericordare che questa tecnologia non consente di creare connessioni verso altri, ben conosciutiprotocolli, come ad esempio telnet, SMTP, IRC, etc., per due distinti motivi: in primo luogo lo useragent implementa una policy che blocca laccesso verso porte riservate a servizi conosciuti (fannoeccezione solo la 80 e la 443). In seconda istanza le comunicazioni viaggiano allinterno di un nuovo especifico protocollo, chiamato con molta fantasia The WebSocket Protocol(http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-03) che richiama per certi aspetti,soprattutto durante lhandshake(http://en.wikipedia.org/wiki/WebSockets#WebSocket_Protocol_Handshake), una conversazioneHTTP.Le specifcheLutilizzo di queste API è assolutamente didascalico, ci troviamo di fronte infatti a poco più di tremetodi; vediamoli insieme:var echo_service = new WebSocket(ws://echo.websocket.org);La creazione di un nuovo WebSocket richiede come unico parametro obbligatorio lurl verso laquale si vuole stabilire la connessione. Il protocollo può essere ws o wss, dove il secondo indica larichiesta di una connessione sicura. Opzionalmente è possibile passare al costruttore anche unastringa o un array di sub-protocolli: valori arbitrari utili per comunicare al server un elenco di serviziche loggetto in costruzione può supportare. Ad esempio un server di chat potrebbe rispondere solo arichieste con protocollo server_di_chat, e via dicendo...echo_service.onmessage = function(event){ alert(event.data);}Una volta creato un nuovo WebSocket, il funzionamento dello stesso diventa praticamente identico,nella forma, a quello già esposto per la comunicazione tra Worker: la funzione associataallhandleronmessage viene invocata ogniqualvolta dal server proviene un messaggio,echo_service.onopen = function(){ echo_service.send("hello!");}mentre la funzione send provvede allinvio, verso il server remoto, del testo passato comeargomento. Da notare che linvio deve essere necessariamente subordinato alla condizione diavvenuta connessione, notificata tramite levento onopen. Esistono altri eventi allinterno del ciclo vitadi un WebSocket: onclose e onerror; vediamoli insieme completando lesempio:<!doctype html>
  • 107. <html><head> <title> WebSocket: Echo Server </title> <script> append = function(text){ document.getElementById("eventi_websocket").insertAdjacentHTML(beforeend, "<li>" + text + ";</li>" ); } window.onload = function(){ var echo_service = new WebSocket(ws://echo.websocket.org); echo_service.onmessage = function(event){ append("messaggio ricevuto") alert(event.data); echo_service.close(); } echo_service.onopen = function(){ append("connessione effettuata") echo_service.send("hello!"); } echo_service.onclose = function(){ append("connessione chiusa"); } echo_service.onerror = function(){ append("errore nella connessione"); } } </script></head><body> <ul id="eventi_websocket"> </ul></body></html>In questo esempio è stato introdotto anche il metodo close, utile per terminare una connessione.Eseguiamo lesempio allinterno di Chromium (figura 1):Figura 1 (click per ingrandire)
  • 108. (http://www.html.it/guide/esempi/html5/imgs/lezione_websocket/1.jpg)Prima di proseguire è bene ricordare che il server utilizzato per questo esempio (demo(esempi/lezione_websockets/websocket.html)): echo.websocket.org ha la peculiarità, come il nomestesso suggerisce, di rispondere ad ogni messaggio con lo stesso testo ricevuto.Un esempioNel prossimo capitolo estenderemo il progetto guida in modo che ogni FiveBoard sia connessa adun server centrale; creeremo quindi un viewer: una pagina html capace di connettersi ad unaFiveBoard registrata presso il server e leggerne il testo mano mano esso viene digitato. Ecco loschema (figura 2):Figura 2 (click per ingrandire)(http://www.html.it/guide/esempi/html5/imgs/lezione_websocket/2.jpg)Per poter raggiungere questo obiettivo è necessario scrivere anche del codice in un linguaggio server-side. Tale codice servirà per creare e istruire il WebSocket Server, al quale le varie pagine dovrannoconnettersi; ai fini di questo esempio non è necessario cercare un servizio di hosting sul qualeinstallare il codice del WebSocket Server: la nostra macchina di sviluppo andrà benissimo. Per questa
  • 109. implementazione utilizzeremo Ruby (http://ruby.html.it), un linguaggio di programmazione elegantee conciso. Linstallazione dellinterprete Ruby è veramente facile ed il codice che utilizzeremo moltoleggibile. Per prima cosa colleghiamoci al portale ufficiale: http://www.ruby-lang.org/it/downloads/(http://www.ruby-lang.org/it/downloads/) e selezioniamo la procedura di installazione dedicata alnostro sistema operativo, quindi apriamo una console di comando (a volte chiamata anche terminale)e digitiamo:gem install em-websocketPer installare la libreria necessaria allo sviluppo del WebSocket Server (per alcuni sistemi operativi ènecessario anteporre sudo allistruzione).Creiamo ora un file websocket_server.rb e modifichiamone il contenuto come segue:require rubygemsrequire em-websocketEventMachine.run { @channels = Hash.new {|h,k| h[k] = EM::Channel.new } EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080, :debug => true) do| ws| ws.onopen do sid = nil fiveboard_channel = nil ws.onmessage do |msg| command, value = msg.split(":", 2); case command when registra fiveboard_channel = @channels[value] sid = fiveboard_channel.subscribe { |txt| ws.send(txt) } when aggiorna fiveboard_channel.push(testo: + value) end end ws.onclose do fiveboard_channel.unsubscribe(sid) end endendputs "Il server è correttamente partito"}Seppur possiate essere non abituati a questo linguaggio il codice è tutto sommato comprensibile esuccinto, ecco la spiegazione dellalgoritmo: Con listruzione WebSocket.start(.. lapplicazione si mette in attesa di connessioni websocket sulla porta 8080; ogni connessione in ingresso viene memorizzata nella variabile ws e causa lesecuzione delle successive istruzioni (quelle comprese nellattiguo blocco do..end).
  • 110. Alla ricezione di un messaggio attraverso una connessione ws (ws.onmessage) il server si comporta dividendo il testo ricevuto secondo la solita convenzione comando:valore ed agendo in modo diverso a seconda che il comando sia registra o aggiorna. Nel caso il messaggio sia registra:titolo_del_documento il server aggiungerà la connessione attuale ad un canale che porta il nome del valore del messaggio (in questo caso titolo_del_documento). In questo modo tutte le pagine che vorranno osservare il documento A non dovranno far altro che inviare al WebSocket Server il messaggio registra:A. Nel caso il messaggio sia aggiorna:testo_del_documento il server si comporterà semplicemente inviando lungo il canale associato alla connessione corrente il valore del messaggio (in questo caso testo_del_documento), propagandolo in questo modo a tutte le connessioni registrate al canale. Infine con listruzione ws.onclose do... si gestisce, in caso di disconnessione del client, la rimozione di ws dal canale presso il quale si era registrata.Eseguiamo il server portandoci con il terminale nella posizione dello script e digitando:ruby websocket_server.rbUn messaggio, Il server è correttamente partito, dovrebbe confermare la bontà del nostro operato.Dedichiamoci ora alle API Javascript ed alla loro implementazione, per prima cosa editiamo il filejs/application.js per fare in modo che ogni FiveBoard si registri presso il server ed invii segnali diaggiornamento ad ogni modifica del testo, ecco il codice da inserire allinterno della funzionewindow.onload:// allinterno di window.onload, js/application.js// queste due istruzioni sono state spostate dalla loro precedente posizionetitolo_fiveboard = prompt("Seleziona il titolo per questa FiveBoard");document.title = "FB: " + titolo_fiveboard;// creazione di un nuovo socket verso il server Rubywebsocket = new WebSocket(ws://0.0.0.0:8080);websocket.onopen = function(){ // invio del comando registra websocket.send("registra:" + titolo_fiveboard);}// ad ogni variazione di input segue linvio del comando aggiorna // verso il server Rubydocument.forms[form_da_ricordare].elements[testo_da_ricordare].oninput = function(event){websocket.send("aggiorna:" + event.target.value);}Anche in questo caso limplementazione risulta abbastanza leggibile; unico appunto da faresullevento oninput, anchesso novità introdotta dalle specifiche HTML5, che viene invocato ad ogniattività di input (pressione di un tasto, copia ed incolla, drag and drop,...) sullelemento in oggetto.Completiamo lesempio con la creazione della semplicissima pagina viewer.html:<!doctype html><html>
  • 111. <head> <title>FiveBoard Viewer</title> <script> window.onload = function(){ var documento_da_visionare = prompt("Inserisci il nome del documento che vuoi osservare"); var websocket = new WebSocket(ws://0.0.0.0:8080); websocket.onopen = function(){ document.title = "VB: " + documento_da_visionare; websocket.send("registra:" + documento_da_visionare); } websocket.onmessage = function(evento){ nome_comando = evento.data.split(":")[0] valore_comando = evento.data.substr(nome_comando.length + 1); switch (nome_comando){ case testo: document.getElementById(documento_in_visione).value = valore_comando; break; } } } </script></head><body> <textarea id="documento_in_visione" readonly>Aspettando il primo aggiornamento...</textarea></body></html>In questo caso la pagina è istruita nel reagire alla ricezione di un messaggio da parte del WebSocketServer; il valore ricevuto viene infatti gestito con la solita convenzione comando:valore e, nel caso ilcomando sia testo, il valore viene inserito allinterno di una textarea preposta.Bene, eseguiamo una prova di funzionamento(http://www.html.it/guide/esempi/html5/esempi/lezione_websockets/fiveboard/index.html):sincerandoci di aver lanciato il WebSocket Server navighiamo prima sulla pagina index.html ecreiamo un nuovo documento esempio1, quindi apriamo una nuova finestra e puntiamola allindirizzodi viewer.html: alla richiesta del nome del documento inseriamo anche qui esempio1 in modo dalegare il viewer alla fiveboard.Ora proviamo a digitare alcuni caratteri sulla prima finestra e noteremo che, attraverso il server,questi sono propagati in tempo reale alla seconda! Ovviamente il tutto funzionerebbe anche se laconversazione avvenisse tra due macchine distinte attraverso un server remoto; nellimmagineseguente si può notare una fiveboard aperta sulliPad ed il suo corrispondente viewer visibile su di unportatile; in alto i messaggi di log del WebSocket Server (figura 3).Figura 3 (click per ingrandire)
  • 112. (http://www.html.it/guide/esempi/html5/imgs/lezione_websocket/3.jpg)ConclusioniI WebSocket, sono nella loro estrema semplicità, degli strumenti incredibilmente potenti; a riprova diquesto fatto la rete ha già incominciato ad offrire interessanti prospettive di utilizzo nonostantelinnegabile giovinezza di queste API. Tra le soluzioni degne di nota merita sicuramente una citazionePusher (http://pusherapp.com/), un servizio che offre la possibilità di gestire eventi real-timeattraverso lutilizzo di WebSocket. Un po più artigianale, ma altrettanto valido è http://jsterm.com/(http://jsterm.com/), unapplicazione che consente di collegarsi a server remoti utilizzando un proxy,scritto in node.js, tra il protocollo WebSocket e Telnet.Recentemente lo sviluppo delle API è stato frenato dalla scoperta di una seria vulnerabilità[documento PDF] (http://www.adambarth.com/experimental/websocket.pdf) legata al potenzialecomportamento di un caching proxy che può essere indotto, attraverso lutilizzo di WebSocket ad-hoc,a modificare il contenuto delle informazioni consegnate ad altri client. La vulnerabilità è statacorrettamente risolta dalla versione 0.7 del protocollo ma sfortunatamente le versioni 4 e 5 di Firefox,rilasciate prima del fix, hanno i websocket disabilitati per default; la versione 6 del browser dovrebbeperò ripristinare il funzionamento out-of-the-box di questa interessantissima feature.Tabella del supporto sui browserAPI e Web ApplicationsWebSockets No 4.0+ (parziale) 5.0+ 7.0+ 11.0+ (parziale) WebSockets APILe WebSockets API introducono, nella loro estrema semplicità, una funzionalità tra le più attese ed
  • 113. emulate: la possibilità di stabilire e mantenere una connessione dati tra browser e serverremotosulla quale far transitare messaggi in entrambe le direzioni. Le attuali specifiche, che lascianoben poco spazio per implementazioni del genere, hanno, nel corso degli anni, dato luogo aworkaround più o meno esotici tra i quali lutilizzo di socket in Flash pilotati via Javascript e dellafamosa tecnica di long polling (lutilizzo continuo di chiamate AJAX mantenute aperte fino allaricezione del dato o al tempo di timeout). Le nuove API offrono invece un meccanismo ben piùsemplice grazie alloggetto WebSocket, al metodo send e allevento onmessage.Prima di passare alla visione delle specifiche e al dovuto esempio di implementazione è importantericordare che questa tecnologia non consente di creare connessioni verso altri, ben conosciutiprotocolli, come ad esempio telnet, SMTP, IRC, etc., per due distinti motivi: in primo luogo lo useragent implementa una policy che blocca laccesso verso porte riservate a servizi conosciuti (fannoeccezione solo la 80 e la 443). In seconda istanza le comunicazioni viaggiano allinterno di un nuovo especifico protocollo, chiamato con molta fantasia The WebSocket Protocol(http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-03) che richiama per certi aspetti,soprattutto durante lhandshake(http://en.wikipedia.org/wiki/WebSockets#WebSocket_Protocol_Handshake), una conversazioneHTTP.Le specifcheLutilizzo di queste API è assolutamente didascalico, ci troviamo di fronte infatti a poco più di tremetodi; vediamoli insieme:var echo_service = new WebSocket(ws://echo.websocket.org);La creazione di un nuovo WebSocket richiede come unico parametro obbligatorio lurl verso laquale si vuole stabilire la connessione. Il protocollo può essere ws o wss, dove il secondo indica larichiesta di una connessione sicura. Opzionalmente è possibile passare al costruttore anche unastringa o un array di sub-protocolli: valori arbitrari utili per comunicare al server un elenco di serviziche loggetto in costruzione può supportare. Ad esempio un server di chat potrebbe rispondere solo arichieste con protocollo server_di_chat, e via dicendo...echo_service.onmessage = function(event){ alert(event.data);}Una volta creato un nuovo WebSocket, il funzionamento dello stesso diventa praticamente identico,nella forma, a quello già esposto per la comunicazione tra Worker: la funzione associataallhandleronmessage viene invocata ogniqualvolta dal server proviene un messaggio,echo_service.onopen = function(){ echo_service.send("hello!");}mentre la funzione send provvede allinvio, verso il server remoto, del testo passato comeargomento. Da notare che linvio deve essere necessariamente subordinato alla condizione diavvenuta connessione, notificata tramite levento onopen. Esistono altri eventi allinterno del ciclo vitadi un WebSocket: onclose e onerror; vediamoli insieme completando lesempio:<!doctype html>
  • 114. <html><head> <title> WebSocket: Echo Server </title> <script> append = function(text){ document.getElementById("eventi_websocket").insertAdjacentHTML(beforeend, "<li>" + text + ";</li>" ); } window.onload = function(){ var echo_service = new WebSocket(ws://echo.websocket.org); echo_service.onmessage = function(event){ append("messaggio ricevuto") alert(event.data); echo_service.close(); } echo_service.onopen = function(){ append("connessione effettuata") echo_service.send("hello!"); } echo_service.onclose = function(){ append("connessione chiusa"); } echo_service.onerror = function(){ append("errore nella connessione"); } } </script></head><body> <ul id="eventi_websocket"> </ul></body></html>In questo esempio è stato introdotto anche il metodo close, utile per terminare una connessione.Eseguiamo lesempio allinterno di Chromium (figura 1):Figura 1 (click per ingrandire)
  • 115. (http://www.html.it/guide/esempi/html5/imgs/lezione_websocket/1.jpg)Prima di proseguire è bene ricordare che il server utilizzato per questo esempio (demo(esempi/lezione_websockets/websocket.html)): echo.websocket.org ha la peculiarità, come il nomestesso suggerisce, di rispondere ad ogni messaggio con lo stesso testo ricevuto.Un esempioNel prossimo capitolo estenderemo il progetto guida in modo che ogni FiveBoard sia connessa adun server centrale; creeremo quindi un viewer: una pagina html capace di connettersi ad unaFiveBoard registrata presso il server e leggerne il testo mano mano esso viene digitato. Ecco loschema (figura 2):Figura 2 (click per ingrandire)(http://www.html.it/guide/esempi/html5/imgs/lezione_websocket/2.jpg)Per poter raggiungere questo obiettivo è necessario scrivere anche del codice in un linguaggio server-side. Tale codice servirà per creare e istruire il WebSocket Server, al quale le varie pagine dovrannoconnettersi; ai fini di questo esempio non è necessario cercare un servizio di hosting sul qualeinstallare il codice del WebSocket Server: la nostra macchina di sviluppo andrà benissimo. Per questa
  • 116. implementazione utilizzeremo Ruby (http://ruby.html.it), un linguaggio di programmazione elegantee conciso. Linstallazione dellinterprete Ruby è veramente facile ed il codice che utilizzeremo moltoleggibile. Per prima cosa colleghiamoci al portale ufficiale: http://www.ruby-lang.org/it/downloads/(http://www.ruby-lang.org/it/downloads/) e selezioniamo la procedura di installazione dedicata alnostro sistema operativo, quindi apriamo una console di comando (a volte chiamata anche terminale)e digitiamo:gem install em-websocketPer installare la libreria necessaria allo sviluppo del WebSocket Server (per alcuni sistemi operativi ènecessario anteporre sudo allistruzione).Creiamo ora un file websocket_server.rb e modifichiamone il contenuto come segue:require rubygemsrequire em-websocketEventMachine.run { @channels = Hash.new {|h,k| h[k] = EM::Channel.new } EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080, :debug => true) do| ws| ws.onopen do sid = nil fiveboard_channel = nil ws.onmessage do |msg| command, value = msg.split(":", 2); case command when registra fiveboard_channel = @channels[value] sid = fiveboard_channel.subscribe { |txt| ws.send(txt) } when aggiorna fiveboard_channel.push(testo: + value) end end ws.onclose do fiveboard_channel.unsubscribe(sid) end endendputs "Il server è correttamente partito"}Seppur possiate essere non abituati a questo linguaggio il codice è tutto sommato comprensibile esuccinto, ecco la spiegazione dellalgoritmo: Con listruzione WebSocket.start(.. lapplicazione si mette in attesa di connessioni websocket sulla porta 8080; ogni connessione in ingresso viene memorizzata nella variabile ws e causa lesecuzione delle successive istruzioni (quelle comprese nellattiguo blocco do..end).
  • 117. Alla ricezione di un messaggio attraverso una connessione ws (ws.onmessage) il server si comporta dividendo il testo ricevuto secondo la solita convenzione comando:valore ed agendo in modo diverso a seconda che il comando sia registra o aggiorna. Nel caso il messaggio sia registra:titolo_del_documento il server aggiungerà la connessione attuale ad un canale che porta il nome del valore del messaggio (in questo caso titolo_del_documento). In questo modo tutte le pagine che vorranno osservare il documento A non dovranno far altro che inviare al WebSocket Server il messaggio registra:A. Nel caso il messaggio sia aggiorna:testo_del_documento il server si comporterà semplicemente inviando lungo il canale associato alla connessione corrente il valore del messaggio (in questo caso testo_del_documento), propagandolo in questo modo a tutte le connessioni registrate al canale. Infine con listruzione ws.onclose do... si gestisce, in caso di disconnessione del client, la rimozione di ws dal canale presso il quale si era registrata.Eseguiamo il server portandoci con il terminale nella posizione dello script e digitando:ruby websocket_server.rbUn messaggio, Il server è correttamente partito, dovrebbe confermare la bontà del nostro operato.Dedichiamoci ora alle API Javascript ed alla loro implementazione, per prima cosa editiamo il filejs/application.js per fare in modo che ogni FiveBoard si registri presso il server ed invii segnali diaggiornamento ad ogni modifica del testo, ecco il codice da inserire allinterno della funzionewindow.onload:// allinterno di window.onload, js/application.js// queste due istruzioni sono state spostate dalla loro precedente posizionetitolo_fiveboard = prompt("Seleziona il titolo per questa FiveBoard");document.title = "FB: " + titolo_fiveboard;// creazione di un nuovo socket verso il server Rubywebsocket = new WebSocket(ws://0.0.0.0:8080);websocket.onopen = function(){ // invio del comando registra websocket.send("registra:" + titolo_fiveboard);}// ad ogni variazione di input segue linvio del comando aggiorna // verso il server Rubydocument.forms[form_da_ricordare].elements[testo_da_ricordare].oninput = function(event){websocket.send("aggiorna:" + event.target.value);}Anche in questo caso limplementazione risulta abbastanza leggibile; unico appunto da faresullevento oninput, anchesso novità introdotta dalle specifiche HTML5, che viene invocato ad ogniattività di input (pressione di un tasto, copia ed incolla, drag and drop,...) sullelemento in oggetto.Completiamo lesempio con la creazione della semplicissima pagina viewer.html:<!doctype html><html>
  • 118. <head> <title>FiveBoard Viewer</title> <script> window.onload = function(){ var documento_da_visionare = prompt("Inserisci il nome del documento che vuoi osservare"); var websocket = new WebSocket(ws://0.0.0.0:8080); websocket.onopen = function(){ document.title = "VB: " + documento_da_visionare; websocket.send("registra:" + documento_da_visionare); } websocket.onmessage = function(evento){ nome_comando = evento.data.split(":")[0] valore_comando = evento.data.substr(nome_comando.length + 1); switch (nome_comando){ case testo: document.getElementById(documento_in_visione).value = valore_comando; break; } } } </script></head><body> <textarea id="documento_in_visione" readonly>Aspettando il primo aggiornamento...</textarea></body></html>In questo caso la pagina è istruita nel reagire alla ricezione di un messaggio da parte del WebSocketServer; il valore ricevuto viene infatti gestito con la solita convenzione comando:valore e, nel caso ilcomando sia testo, il valore viene inserito allinterno di una textarea preposta.Bene, eseguiamo una prova di funzionamento(http://www.html.it/guide/esempi/html5/esempi/lezione_websockets/fiveboard/index.html):sincerandoci di aver lanciato il WebSocket Server navighiamo prima sulla pagina index.html ecreiamo un nuovo documento esempio1, quindi apriamo una nuova finestra e puntiamola allindirizzodi viewer.html: alla richiesta del nome del documento inseriamo anche qui esempio1 in modo dalegare il viewer alla fiveboard.Ora proviamo a digitare alcuni caratteri sulla prima finestra e noteremo che, attraverso il server,questi sono propagati in tempo reale alla seconda! Ovviamente il tutto funzionerebbe anche se laconversazione avvenisse tra due macchine distinte attraverso un server remoto; nellimmagineseguente si può notare una fiveboard aperta sulliPad ed il suo corrispondente viewer visibile su di unportatile; in alto i messaggi di log del WebSocket Server (figura 3).Figura 3 (click per ingrandire)
  • 119. (http://www.html.it/guide/esempi/html5/imgs/lezione_websocket/3.jpg)ConclusioniI WebSocket, sono nella loro estrema semplicità, degli strumenti incredibilmente potenti; a riprova diquesto fatto la rete ha già incominciato ad offrire interessanti prospettive di utilizzo nonostantelinnegabile giovinezza di queste API. Tra le soluzioni degne di nota merita sicuramente una citazionePusher (http://pusherapp.com/), un servizio che offre la possibilità di gestire eventi real-timeattraverso lutilizzo di WebSocket. Un po più artigianale, ma altrettanto valido è http://jsterm.com/(http://jsterm.com/), unapplicazione che consente di collegarsi a server remoti utilizzando un proxy,scritto in node.js, tra il protocollo WebSocket e Telnet.Recentemente lo sviluppo delle API è stato frenato dalla scoperta di una seria vulnerabilità[documento PDF] (http://www.adambarth.com/experimental/websocket.pdf) legata al potenzialecomportamento di un caching proxy che può essere indotto, attraverso lutilizzo di WebSocket ad-hoc,a modificare il contenuto delle informazioni consegnate ad altri client. La vulnerabilità è statacorrettamente risolta dalla versione 0.7 del protocollo ma sfortunatamente le versioni 4 e 5 di Firefox,rilasciate prima del fix, hanno i websocket disabilitati per default; la versione 6 del browser dovrebbeperò ripristinare il funzionamento out-of-the-box di questa interessantissima feature.Tabella del supporto sui browserAPI e Web ApplicationsWebSockets No 4.0+ (parziale) 5.0+ 7.0+ 11.0+ (parziale) Drag and Drop
  • 120. La soluzione al Drag and Drop proposta dalle specifiche HTML5(http://dev.w3.org/html5/spec/editing.html#dnd) va ben oltre la metafora classica emulata in modoeccelso (http://jqueryui.com/demos/draggable/) da librerie come JQurey e similari. Certo, anche queltipo di comportamento è possibile, ma stiamo solo raschiando la superficie di una feature ben piùcomplessa, articolata e potente. Un assaggio più consistente delle reali capacità del Drag and Drop èofferto dalla versione HTML5 del famoso client di posta Gmail: trascinando un file al di sopra dellapagina per la composizione di un nuovo messaggio si evidenza una zona verde, rilasciando ildocumento al di sopra di tale zona possiamo assistere all’upload dello stesso; ed il tutto funzionaanche con più file contemporaneamente! Prima di passare ad una analisi delle specifiche è benequindi capire che questo meccanismo non è stato studiato solo per riordinare liste o spostare oggettiin un carrello ma deve essere inteso come vero e proprio sistema di input sia per informazioni internealla pagina sia esterne.Le specificheGli attori coinvolti in queste API sono essenzialmente tre, e non è necessario che siano tutti presentiad ogni implementazione. Stiamo parlando dell’oggetto che subisce il drag, della struttura checontiene i dati che intendiamo trasferire attraverso il drop, e dell’oggetto che accetta il drop.Ecco come funziona una sessione completa di Drag and Drop:<ul id="elementi_da_trascinare" ondragstart="iniziaTrascinamento(event)"> <li draggable="true" data-icona="http://bit.ly/h5Khyt" data-valore="0.5">50 Cents</li> <li draggable="true" data-icona="http://bit.ly/gnyFfh" data-valore="1" > 1 Euro </li> <li draggable="true" data-icona="http://bit.ly/eXq6y5" data-valore="2" > 2 Euro </li> <li draggable="true" data-icona="http://bit.ly/hiftBg" data-valore="10"> 10 Euro </li></ul>In primo luogo è necessario l’utilizzo dell’attributo globale draggable="true" per specificare glielementi che vogliamo rendere trascinabili; utilizziamo inoltre i campi data-* per salvare informazioniche potranno tornare utili più tardi, come l’url dell’icona della moneta e il suo valore numerico. Ilpasso successivo consiste nel definire la funzione associata all’evento che notifica l’inizio di untrascinamento (ondragstart), nel nostro caso l’evento è stato associato all’ul, in quanto sottendel’intero elenco degli elementi con il comportamento drag abilitato.<script> iniziaTrascinamento = function(evento){ evento.dataTransfer.setData("text", event.target.dataset.valore); evento.dataTransfer.effectAllowed = copy; icona = document.createElement(img); icona.src = evento.target.dataset.icona; evento.dataTransfer.setDragImage(icona, -10, -10); }</script>Nell’argomento evento lo user-agent si premura di fornirci tutto il necessario per gestire il
  • 121. trascinamento dell’elemento. Nella prima riga della funzione viene invocata la strutturadataTransfer, atta a contenere i dati che vogliamo siano disponibili all’oggetto incaricato del drop;con il metodo setData richiediamo poi l’inserimento di un nuovo valore all’interno di tale struttura.Stando alle specifiche potremmo identificare questo valore con un’etichetta (usando il primoargomento, ad esempio ‘valuta’), in questo modo saremmo poi in grado di istruire l’area di drop adaccettare solo il rilascio di elementi con tale etichetta; nella realtà questa funzionalità non è ancorasupportata in modo sufficiente (http://code.google.com/p/chromium/issues/detail?id=31037) efunziona solo con etichette text o url. Come secondo argomento alla chiamata specifichiamo invece ilcontenuto del campo ‘data-valore’ dell’elemento che sta subendo il trascinamento.Nella riga successiva, con l’istruzione evento.effectAllowed = copy segnaliamo allo user-agentche l’azione di drag è da intendersi come copia e non, ad esempio, come spostamento (in quel casosarebbe stato move). È importante notare che tale segnalazione non implica di per sé nessuncambiamento alla dinamica dello user-agent nei confronti di questo drag and drop (se non qualcheaccortezza grafica, come vedremo poi) ma ci da ancora una volta la possibilità di filtrare in fase didrop gli elementi che rilasciamo accettando, ad esempio, solamente azioni di tipo copy.Le due righe di codice seguenti servono invece per creare una immagine avente come src il campodata-icona dell’elemento che stiamo trascinando; infine con l’ultimaistruzione,evento.dataTransfer.setDragImage(icona, -10, -10), comunichiamo al dataTransferdi usare l’immagine appena generata come oggetto da visualizzare durante il trascinamento.Se proviamo ad includere i due frammenti di codice in una classica struttura HTML5 e ad eseguirli conChromium avremo questo effetto (figura 1):Figura 1Bene, ora creiamo l’oggetto di drop e gestiamo l’azione di rilascio:...</ul> <img id="portamonete" dropzone="copy s:text" draggable="false" src="http://bit.ly/gZH4H5" ondragenter="ingressoInZonaDiDrop(event)" ondragleave="uscitaZonaDiDrop(event)" ondragover="trascinamentoInZonaDiDrop(event)"
  • 122. ondrop="rilascioDellOggettoTrascinato(event)" > <p> Il portamonete contiene: <output id="sommatoria">0</output> euro</p>Così come ogni elemento HTML può essere impostato come trascinabile grazie all’attributodraggable=true, anche il ruolo di area di drop può essere delegato a qualsiasi tag. In questo casoabbiamo scelto di utilizzare un’immagine di un portamonete nel quale riporremo i nostri risparmi.Diamo una scorsa agli attributi che abbiamo impostato: dropzone: con questo attributo, purtroppo ancora poco supportato, è possibile specificare in modo sintetico ed efficace le varie tipologie di dati per i quali l’area di drop è abilitata. I primi comandi, separati da uno spazio, indicano le tipologie di effectAllowed supportate (in questo caso solamente copy) mentre le restanti istruzioni, nel formato s:testo o f:testo rappresentano in caso di s:testole etichette supportate, o i mime-type supportati nel caso di f:testo. La particella s indica che il contenuto del dataTransfer deve essere di natura testuale (come nell’esempio che stiamo studiando), mentre la particella f implica che l’area di drop accetti solamente file, come ad esempio succede nel caso dell’aggiunta di allegati alla Gmail. Validi esempi di valorizzazione di questo attributo sono i seguenti:-- Accetta copy per file di tipo png e jpegdropzone="copy f:image/png f:image/jpeg"-- Accetta move e copy per etichette "valuta"dropzone="move copy s:valuta" draggable: conosciamo già questo attributo; in ogni caso è importante segnalare che qui è stato utilizzato per informare lo user-agent di non rendere trascinabile questa immagine. Infatti nella maggioranza dei browser le immagini lo sono di default; ondragenter, ondragmove e ondragleave: questi tre eventi vengono invocati quando l’elemento viene trascinato all’interno di un’area di drop (ondragenter), mosso all’interno della stessa(ondragmove) e infine spostato nuovamente all’esterno dell’area (ondragleave); ondrop: l’evento chiave dell’intero processo, viene invocato al rilascio di un elemento al di sopra di un area di drop.Ottimo! Non ci resta che completare questa panoramica delle specifiche osservando una possibileimplementazione degli eventi appena descritti:... ingressoInZonaDiDrop = function(evento){ evento.target.src = "http://bit.ly/gRo6cc"; evento.preventDefault(); } uscitaZonaDiDrop = function(evento){ evento.target.src = "http://bit.ly/gZH4H5"; } trascinamentoInZonaDiDrop = function(evento){ evento.dataTransfer.dropEffect = copy;
  • 123. evento.preventDefault(); } rilascioDellOggettoTrascinato = function(evento){ sommatoria = document.getElementById("sommatoria"); sommatoria.innerHTML = parseFloat(sommatoria.innerHTML) + parseFloat(evento.dataTransfer.getData("text")); evento.target.src = "http://bit.ly/gZH4H5"; }...L’istruzione che merita maggiore attenzione è sicuramente preventDefault() che, se posizionataall’interno di un evento, impedisce al browser di attivare il proprio comportamento di default. Inquesto caso la funzione in questione è stata utilizzata in ingressoInZonaDiDrop per impedire che ilbrowser negasse l’accesso al drop (comportamento di default) ed in trascinamentoInZonaDiDrop perevitare l’animazione di ‘ritorno’ degli elementi draggati al loro rilascio.Per il resto le due funzioni associate a ondragenter e ondragleave si preoccupano solamente dialternare, tra chiusa e aperta, l’immagine del portamonete all’ingresso (o uscita) di un elementotrascinato al di sopra di esso. trascinamentoInZonaDiDrop deve invece preoccuparsi nuovamente disegnalare il supporto al solo effetto copy; questo accorgimento non sarebbe necessario con un pienosupporto dell’attributo dropzone.Infine la funzione legata all’evento ondrop contiene l’importante metodo getData(etichetta),indispensabile per recuperare dal dataTransfer l’ultimo oggetto inserito con l’etichetta richiesta.Eseguiamo il tutto in Chromium notando anche come l’icona del mouse si modifichi durante l’azione didrag and drop ad indicare la copia (figura 2):Figura 2 (click per ingrandire)
  • 124. (http://www.html.it/guide/esempi/html5/imgs/lezione_drag/2.jpg)Ecco la demo (http://www.html.it/guide/esempi/html5/esempi/lezione_drag/demo.html).Un esempioVisto che non abbiamo ancora sperimento il drag and drop di file, utilizziamo il progetto guida perfare alcune prove; in particolare implementiamo la possibilità di rilasciare un file di testo al disopra di una textarea per fare in modo che in questa vi si riversi il contenuto. Questo esempio cidarà anche l’occasione di toccare con mano la potenza delle nuove File API(http://www.w3.org/TR/FileAPI/), in particolare approfondiremo gli oggetti Javascript File, FileListe FileReader: ottimi compagni nel caso sia necessario accedere agli attributi o al contenuto di un fileselezionato (o trascinato) per l’upload.Incominciamo modificando il markup del file index.html per attivare una drop area sulla textarea:<label>Cosa hai in mente? <textarea name="testo_da_ricordare" required autofocus placeholder="La lista della spesa, il teatro di questa sera ..." dropzone="copy f:text/plain" ondragover="consentiIlDrop(event)" ondrop="caricaIlContenutoTestuale(event,this)"> </textarea></label>
  • 125. Fin qui niente di strano, la parte divertente è tutta racchiusa nella definizione delle due funzioni.Vediamole insieme nel file application.js:consentiIlDrop = function(evento){ evento.dataTransfer.dropEffect = copy; evento.preventDefault();}caricaIlContenutoTestuale = function(evento,element){ var files = evento.dataTransfer.files; var reader = new FileReader(); reader.onload = function(evento){ element.value = element.value + evento.target.result; } for(file in files){ reader.readAsBinaryString(files[file]); }}La funzione caricaIlContenutoTestuale merita un approfondimento: il metodo files chiamato sudataTransfer ritorna un elenco di File racchiusi in un oggetto di tipo FileList, che per i nostriscopi è assimilabile ad un array.Successivamente, nella variabile reader, viene caricata un istanza di FileReader, una classepredisposta esclusivamente alla lettura del contenuto degli oggetti di tipo File. Nelle righe successiveviene impostata l’azione associata all’evento onload di reader, che viene invocato al completamentodell’azione di lettura di un file; all’interno di questa azione il contenuto testuale del file(evento.target.result) è concatenato al testo già presente nella textarea. L’ultimo frammento diquesta funzione cicla su tutti i file presenti in files; successivamente su ognuno di essi vienerichiesta la lettura al reader attraverso il metodo readAsBinaryString.Anche per questo esempio abbiamo preparato una demo(http://www.html.it/guide/esempi/html5/esempi/lezione_drag/fiveboard/index.html). Funziona almomento solo su Chromium. Per il test basta creare un file di testo, salvarlo (magari sul desktop) etrascinarlo nella textarea.Tabella del supporto sui browserAPI e Web ApplicationsDrag and Drop No 3.5+ 3.2+ 2.0+ No Geolocation APILe Geolocation Api non sono contenute all’interno dell’HTML5 ma fanno parte di quell’insieme di
  • 126. documenti (http://dev.w3.org/geo/api/spec-source.html) che gravitano attorno alle specifiche; la lorofunzionalità è abbastanza semplice, definire una struttura dati atta a contenere vari datigeospaziali e impostare alcune funzioni di accesso a tali dati. Nessuna menzione viene fatta inmerito ai meccanismi che il browser deve utilizzare per recuperare questi dati, ogni piattaforma èinfatti tenuta ad utilizzare al meglio le informazioni provenienti dal device. Su di un dispositivo mobiledi ultima generazione avremo quindi un set di coordinate provenienti dal sensore GPS, mentre su diun portatile potremo avvalerci del posizionamento legato all’ip della connessione internet.Per proteggere la privacy dell’utente è inoltre fatto divieto di utilizzo delle suddette informazioni senzapreventivo consenso esplicito.Le specificheEsistono praticamente solo due metodi a disposizione, fra l’altro entrambi utili allo stesso scopo:ottenere la posizione corrente. La differenza tra i due, getCurrentPosition e watchPosition, varicercata nella loro periodicità, mentre il primo metodo fornisce il dato una sola volta, il secondo siattiva automaticamente ogniqualvolta la posizione cambi, ad esempio perché l’utente stapasseggiando.La sintassi per invocare questi metodi è la seguente:navigator.geolocation.getCurrentPosition(inCasoDiSuccesso, opzInCasoDiErrore, opzioni);navigator.geolocation.watchPosition(inCasoDiSuccesso, opzInCasoDiErrore, opzioni);Il primo argomento contiene i riferimenti ad una funzione da eseguire al corretto recupero delleinformazioni geospaziali, il secondo argomento, opzionale, punta invece ad una funzione che verràinvocata in caso di errore. L’ultimo parametro, anch’esso facoltativo, può essere utilizzato perspecificare alcune opzioni utilizzando una struttura {opzione1: valore1, ...}. Le opzioni disponibilisono 3: enableHighAccuracy (true/false): questo flag può essere utilizzato per notificare allo user- agent la necessità o meno di ottenere dati il più accurati possibile. L’opzione è stata introdotta in quanto il recupero di informazioni più dettagliate richiede di solito maggiore dispendio di tempo ed energia e, in particolare su device mobile, potrebbe risultare fastidiosa per l’utente; timeout (millisecondi): l’opzione rappresenta il tempo massimo concesso al browser per recuperare la posizione dell’utente. In caso di fallimento verrà invocata la funzione associata al secondo argomento; maximuAge (millisecondi): indica al browser di effettuare una ricerca preventiva nella cache di un dato geospaziale non più vecchio dei millisecondi specificati. Se disponibile tale dato verrà restituito come posizione corrente, altrimenti verrà eseguita la procedura classica.La funzione invocata in caso di successo deve accettare un singolo argomento, un oggetto di tipoPosition che contiene tutte le informazioni recuperate così come un timestamp delle data e ora direcupero.inCasoDiSuccesso = function(position){ alert( "Posizione delle: " + position.timestamp.getHours() + ":" + position.timestamp.getMinutes() + "n" + "Accuratezza delle coordinate: " + position.coords.accuracy + " mt; n" + "Latitudine: " + position.coords.latitude + " gradi; n" + "Longitudine: " + position.coords.longitude + "gradi; n" +
  • 127. "Accuratezza dellaltezza: " + position.coords.altitudeAccuracy + " mt; n" + "Altezza: " + position.coords.altitude + " mt; n" + "Direzione: " + position.coords.heading + " gradin " + "(0 = Nord, 90 = Ovest, 180 = Sud, 270 = Est);n" + "Velocita: " + position.coords.speed + " m/s;" );}Nel frammento di codice appena illustrato possiamo vedere tutte le informazioni estraibili dallastruttura Position; chiaramente, a seconda del device sul quale viene effettuata l’interrogazione, nontutte saranno sempre disponibili; in tal caso il loro valore sarà impostato a null. Nell’immagineseguente il risultato dell’interrogazione eseguita dal mio portatile domestico (notate l’accuratezza!):Figura 1 - (click per ingrandire)(http://www.html.it/guide/esempi/html5/imgs/lezione_geolocation/ishot-437.png)In caso invece si verifichi un errore la funzione preposta deve accettare anch’essa un parametro, unoggetto di tipo PositionError contenente un codice di errore ed un messaggio ad uso di debug,rispettivamente nei metodi code e message.opzInCasoDiErrore = function(error){ alert( "Errore " + error.code + ": " + error.message);}In ultimo ricordiamo che un invocazione del metodo watchPosition può essere successivamenteinterrotta utilizzando la funzione clearWatch, come nell’esempio seguente:<!doctype html><html><head> <title> Un esempio di watchPosition</title> <script>
  • 128. var id_watch = null; inCasoDiSuccesso = function(position){ document.getElementById("posizione_corrente").insertAdjacentHTML(beforeend, "<li> Lat: " + position.coords.latitude + ", Lon: " + position.coords.longitude +); "</li>" ); } sospendiLaRicezione = function(){ navigator.geolocation.clearWatch(id_watch); } window.onload = function(){ id_watch = navigator.geolocation.watchPosition(inCasoDiSuccesso); }</script></head><body> <h1>La tua posizione attuale</h1> <menu type="toolbar"> <button type="button" onclick="sospendiLaRicezione()"> sospendi la ricezione di dati geospaziali </button> </menu> <ul id="posizione_corrente"> </ul></body></html>Sono disponibili le demo per il primo(http://www.html.it/guide/esempi/html5/esempi/lezione_geolocation/geolocation.html) e per ilsecondo esempio(http://www.html.it/guide/esempi/html5/esempi/lezione_geolocation/geolocation_watchposition.html).ConclusioniCome avete potuto notare questo set di API è contemporaneamente facilissimo da utilizzare edestremamente potente. Le possibilità offerte si dilatano enormemente se ci si concentra sul mercatomobile dove la stragrande maggioranza dei device di ultima generazione è equipaggiata con ottimisensori GPS e bussole.Tabella del supporto sui browserAPI e Web ApplicationsGeolocation No 3.6+ 5.0+ 5.0+ 10.6+
  • 129. CanvasUna tela trasparenteIl canvas è un elemento HTML5 rappresentato dal tag <canvas>. Può essere inteso come ilcorrispettivo digitale di una tela trasparente: uno spazio allinterno di una pagina web sul qualeinsistere con specifiche API (http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#the-canvas-element) adatte a tracciare linee, cerchi, rettangoli, immaginie altro ancora. Il canvas è, in estrema sintesi, una grande matrice di pixel, ognuno dei qualimodificabile singolarmente nelle sue quattro componenti RGBA, rosso, verde, blu e alpha, latrasparenza. Tutti siamo a conoscenza di questo elemento HTML5 per una sua semplice attitudine: lapossibilità di replicare i comportamenti fino ad oggi appannaggio della tecnologia Flash. In questoarticolo esploreremo le numerose API disponibili e ne sperimenteremo una buona parte per poiconcentrarci successivamente su di una interessante evoluzione del progetto guida.Le specifichePrima di addentrarci nella giungla dei vari metodi a disposizione per disegnare sul canvas vediamobrevemente larchitettura che contraddistingue il markup dellelemento:<canvas width="200px" height="200px" id="demo_canvas">Contenuto da mostrare in caso il canvas non sia supportato.(quindi anche informazioni per i motori di ricerca).</canvas>Gli unici due attributi disponibili, oltre ai canonici globali, sono width e height, rispettivamentelarghezza e altezza dellelemento.Sotto il profilo JavaScript i metodi disponibili direttamente attraverso questo elemento sono due:toDataUrl e getContext. Il primo, toDataUrl, è fantastico nella sua semplicità: ritorna infatti ilcontenuto del canvas secondo il protocollo data URL (http://tools.ietf.org/html/rfc2397). Questoschema memorizza file di ogni tipo in lunghissime sequenze di caratteri, che poi possono esseresalvati su disco o, se come nel caso del canvas siano immagini, essere utilizzate come attributo src ditag img. Nei prossimi esempi vedremo un utilizzo tangibile di questo metodo, per ora invececoncentriamoci su getContext, vera e propria porta verso le API di disegno. getContext, quandoinvocato, ritorna un oggetto detto contesto del disegno:var canvas = document.getElementById("demo_canvas");var contesto = canvas.getContext("2d");In questa lezione esploreremo solamente i metodi legati al contesto di disegno 2d, come specificatodallargomento utilizzato nello snippet, ma sappiate che esiste già una versione sperimentale dicontesto 3d che sottende un set di API completamente diverso, basato sulle OpenGL ES 2.0 e dettoWebGL.Ma torniamo al contesto 2d: possiamo dividere le funzionalità in esso racchiuse in categorie: path,modificatori, immagine, testo e pixel per pixel; nelle prossime sezioni affronteremo in dettaglioognuno di questi aspetti. Prima di proseguire è però importante evidenziare che il contesto è unoggetto stateful, che mantiene cioè al suo interno dei valori che influiscono sulle operazioni
  • 130. successive; aspettiamoci quindi delle direttive di questo tipo: imposta colore di linea verde; imposta percorso della linea da (0,0) a (10,10); traccia tutti i percorsi di linea.In questo caso, se avessimo usato le corrette API, avremmo ottenuto una linea verde tra i punti (0,0)e (10,10). Linsieme dei valori memorizzati in un contesto viene detto drawing state.PathI metodi di questa categoria sono tutti funzionali al disegno di frammenti geometrici come linee, archie quantaltro: ecco un esempio omnicomprensivo:disegnaBarchetta = function(contesto){ contesto.beginPath(); // sposta il cursore del path nella posizione 40,170 contesto.moveTo(40,170); // crea un subpath linea fino alla posizione 260,170 contesto.lineTo(260,170); // crea un subpath arco che sia tangente alle due linee (260,170 - 150,250) // (150,250 - 40,170) con diametro 150 contesto.arcTo(150,250,40,170,150); contesto.lineTo(40,170); contesto.moveTo(150,170); contesto.lineTo(150,40); contesto.rect(150,40,60,30); // disegna tutti i subpath del path corrente sul canvas usando la // configurazione del drawing state contesto.stroke(); // riempi tutti le aree inscritte dal path corrente usanto la configurazione // del deawing state contesto.fill();}Il concetto principe è il path, ovverosia un insieme di punti uniti fra loro da definite primitivegeometriche (arco, linea,...), dette subpath. Ogni contesto possiede solamente un path attivo pervolta. Per aggiungere un subpath al path attivo si possono utilizzare metodi come lineTo, arcTo,rect e altri. Metodi come stroke e fill vengono applicati a tutti i subpath del path attivo. Perresettare il path attivo, rimuovendo quindi tutti i subpath non ancora disegnati, si utilizza listruzionebeginPath().Eseguiamo lesempio appena mostrato per ottenere il risultato seguente (figura 1):Figura 1
  • 131. Oltre ai subpath mostrati ce ne sono altri, ma il meccanismo di generazione resta sempre lo stesso, lalista completa è disponibile nel documento ufficiale delle specifiche(http://dev.w3.org/html5/2dcontext/#complex-shapes-paths).ModificatoriLe funzioni allinterno di questo gruppo insistono sul drawing state di un canvas, modificando il modoin cui i path, le immagini ed i testi vengono disegnati. Nella categoria si annoverano matrici ditrasformazione (scale, rotate, translate), gestione della trasparenza globale e delle funzionidi composizione nonché impostazioni di colore, di linea e di gradiente. Suona complicato ? Facciamoun po di prove:contesto.scale(0.5,0.5);contesto.rotate(0.5);contesto.translate(300,-100);disegnaBarchetta(contesto);Ecco il risultato, i modificatori impostati vengono applicati alla barchetta (figura 2):Figura 2
  • 132. Utilizziamo ora trasparenza e composizione:contesto.globalAlpha = 0.5;disegnaBarchetta(contesto);contesto.translate(40,-0);contesto.globalCompositeOperation = "source-out";disegnaBarchetta(contesto);Lattributo globalAlpha definisce (da 0.0 a 1.0) il livello di trasparenza che dovrà essere applicato aquanto verrà disegnato sul canvas. globalCompositeOperation ci permette invece di specificare inche modo vogliamo che le immagini vengano sovrapposte: è possibile utilizzare un set di parolechiave per indicare un ben preciso comportamento; in questo caso con source-out chiediamo allouser agent di effettuare una somma tra le trasparenze ottenendo un risultato come questo (figura 3):Figura 3
  • 133. Attenzione, al momento non tutti i browser reagiscono allo stesso modo alle definizioni legate aGlobalCompositeOperation. Infine esaminiamo anche le operazioni legate ai modificatori di colore:contesto.strokeStyle = "#FF0000";contesto.lineWidth = "5";var gradiente = contesto.createRadialGradient(150, 150, 30, 150, 160, 100);gradiente.addColorStop(0.5, #0000FF);gradiente.addColorStop(0.1, #000000);contesto.fillStyle = gradiente;disegnaBarchetta(contesto);Con strokeStyle e fillStyle possiamo impostare le nostre preferenze su come intendiamo debbaessere disegnata la linea di contorno degli oggetti (stroke) ed il loro riempimento (fill). Entrambi gliattributi possono essere valorizzati con stringhe, oggetti di tipo gradient ed oggetti di tipo pattern.In questo caso è mostrato lutilizzo di una semplice stringa di colore rosso per lo stroke e di ungradient radiale con una variazione di colore dal nero al blu per il fill. Lutilizzo delloggetto pattern èsimile, il metodo da utilizzare è contesto.createPattern(immagine, opzionaleRipetizione) doveil secondo argomento riprende le scelte effettuabili via CSS (no-repeat, repeat-x, ecc..) mentre ilprimo può essere valorizzato con con un elemento img, un altro canvas o perfino un elemento video.Ecco il risultato che si ottiene utilizzando il codice visto (figura 4):Figura 4
  • 134. Prima di passare al prossimo gruppo di funzioni citiamo brevemente anche la possibilità diimplementare un ombreggiatura, ecco le istruzioni:contesto.shadowColor = #003300contesto.shadowOffsetX = 10;contesto.shadowOffsetY = 10;contesto.shadowBlur = 30;disegnaBarchetta(contesto);Ed il risultato (figura 5):Figura 5
  • 135. ImmagineLunico metodo appartenente a questo gruppo si chiama drawImage ed è disponibile in un certonumero di varianti; il primo argomento può infatti essere sia un elemento immagine, sia un altrocanvas, sia un elemento di tipo video. Il risultato delloperazione è sempre quello di disegnare sulcontesto invocante limmagine prescelta, rispettando alcuni parametri dimensionali opzionali. Ecco unesempio:var immagine = new Image();immagine.src = "http://img227.imageshack.us/img227/7092/marei.jpg";contesto.drawImage(immagine,0,0);disegnaBarchetta(contesto);E il risultato (figura 6):Figura 6
  • 136. In questo caso chiediamo che limmagine sia disegnata a partire dallangolo in alto a sinistra delcanvas (coordinate 0,0); possiamo però anche specificare una dimensione di destinazione e perfinoun rettangolo di partenza in modo da prelevare solo una porzione di immagine utilizzando i numerosiargomenti opzionali messi a disposizione dalle specifiche.TestoCome il nome del gruppo suggerisce, questi metodi permettono di scrivere porzioni di testoallinterno di un canvas, eccone un esempio:disegnaBarchetta(contesto);contesto.globalCompositeOperation = "source-out";contesto.font = "34px Georgia"contesto.strokeText("Va va va barchetta", 20, 100);contesto.fillText("va, naviga naviga naviga", 20, 140);contesto.fillText("naviga e mai si", 20, 180);contesto.fillText("fermera...", 20, 220);Lattributo font può essere valorizzato allo stesso modo del suo omonimo su CSS, per il restofillText provvede a scrivere il testo desiderato partendo dalla posizione x, y specificata comesecondo e terzo argomento; anche strokeText si comporta in modo simile ma con una piccolavariante che si può facilmente evincere dal risultato dellesecuzione dellesempio. Da notare inoltre ilcomportamento interessante dellapplicazione di un particolare tipo di composizione (figura 7):Figura 7
  • 137. Pixel per PixelCome già anticipato in precedenza, il canvas non è nientaltro che una matrice di valori in formatoRGBA: non stupisce che sia quindi possibile insistere su ogni singolo e specifico pixel dellastessa; ecco un esempio:disegnaBarchetta(contesto);var dati_immagine = contesto.getImageData(0,0, contesto.canvas.width, contesto.canvas.height);var array_dati_immagine = dati_immagine.data;for(var i = 0; i < array_dati_immagine.length; i +=4 ){ array_dati_immagine[i ] = Math.round(Math.random() * 255); array_dati_immagine[i+1] = Math.round(Math.random() * 255); array_dati_immagine[i+2] = Math.round(Math.random() * 255);}dati_immagine.data = array_dati_immagine;contesto.canvas.width = contesto.canvas.width;contesto.putImageData(dati_immagine, 0,0);Il fulcro dello snippet è da ricercarsi nelle due funzioni getImageData e putImageData cherispettivamente prelevano e stampano sul canvas una porzione di immagine delineata dagliargomenti passati. Tale porzione, un oggetto di classe ImageData, possiede in una sua proprietà,data, un lunghissimo array contenente le componenti RGBA di ogni pixel. Il ciclo for presentato nelcodice precedente insiste proprio su questo array assegnando ad ognuna delle tre componenti RGB unvalore randomico. Ecco il risultato (figura 8):Figura 8
  • 138. Per una verifica diretta di quanto visto nel corso della lezione è disponibile questa demo(http://www.html.it/guide/esempi/html5/esempi/lezione_canvas/index.html).Ora che abbiamo almeno unidea delle potenzialità dello strumento che stiamo analizzando,accingiamoci ad una sperimentazione pratica attraverso il progetto guida. Lo vedremo nella prossimalezione.Tabella del supporto sui browserGrafica e Multimedia<canvas> 9.0+ 2.0+ 3.1+ 2.0+ 10.0+ Canvas: un esempio praticoUn esempioOra che abbiamo almeno unidea delle potenzialità dello strumento che stiamo analizzando,accingiamoci ad una sperimentazione pratica attraverso il progetto guida. Quello che faremo saràdare la possibilità agli utenti della fiveboard di disegnare utilizzando un canvas, lo stesso verrà poimemorizzato insieme al testo sul già noto localStorage. Introduciamo anche in questo contesto ilconcetto diEventoCustom, la possibilità cioè di lanciare arbitrariamente eventi in tutto e per tuttosimili a quelli utilizzati dal DOM. Questa feature ci sarà utilissima per mantenere un codice elegante econtemporaneamente sincronizzare salvataggio e recupero di testo e canvas dal localStorage;aggiungiamo ad application.js il seguente metodo:
  • 139. lanciaEvento = function(nome_evento){ var evento = document.createEvent("CustomEvent"); evento.initCustomEvent(nome_evento, true, true, titolo_fiveboard); document.dispatchEvent(evento);}Eliminiamo successivamente dallo stesso file le funzioni salvaIlDato e recuperaIlDato sostituendolecon le seguenti:salvaAppunti = function(evento){ localStorage.setItem("fb_" + evento.detail, document.forms[form_da_ricordare].elements[testo_da_ricordare].value ); alert("Appunti salvati");}recuperaAppunti = function(evento){ document.forms[form_da_ricordare].elements[testo_da_ricordare].value =localStorage.getItem("fb_" + evento.detail); alert("Appunti recuperati");}document.addEventListener(salvadato, salvaAppunti);document.addEventListener(recuperadato, recuperaAppunti);Bene, ora abbiamo creato le due funzioni e le abbiamo registrate rispettivamente agli eventi custom‘salvadato’ e ‘recuperadato’; ora non ci resta che scatenare questi eventi al click dei bottoni del fileindex.html, modifichiamo quindi come segue:... <menu type="toolbar"> <button type="button" onclick="lanciaEvento(salvadato);"> Memorizza quanto scritto </button> <button type="button" onclick="lanciaEvento(recuperadato);"> Recupera lultimo testo memorizzato </button> </menu>...Ottimo! Ora possiamo aggiungere un canvas poco prima della fine della pagina e procedere con ilnostro esperimento:... <canvas id="drawboard"></canvas> </form>...
  • 140. In un file chiamato canvas.js, sempre nella cartella js, scriviamo:var ctx = null;var started = false;iniziaDisegno = function(evento){ ctx.beginPath(); ctx.moveTo(evento.offsetX,evento.offsetY); started = true;}disegna = function(evento){ if(started){ ctx.lineTo(evento.offsetX,evento.offsetY); ctx.stroke(); }}fermaDisegno = function(evento){ ctx.closePath(); started = false;}salvaCanvas = function(evento){ localStorage.setItem("canvas_fb_" + evento.detail, ctx.canvas.toDataURL(image/png)); alert("Canvas salvato");}recuperaCanvas = function(evento){ var immagine_salvata = localStorage.getItem("canvas_fb_" + evento.detail); if(immagine_salvata == null) return; var img = new Image(); img.src = immagine_salvata; ctx.canvas.width = ctx.canvas.width; ctx.drawImage(img, 0, 0); alert("Canvas recuperato");}attivaIlCanvas = function(evento){ ctx = document.querySelector(canvas).getContext(2d); ctx.canvas.addEventListener(mousedown , iniziaDisegno,false ); ctx.canvas.addEventListener(mousemove , disegna ,false ); ctx.canvas.addEventListener(mouseup , fermaDisegno ,false ); ctx.canvas.addEventListener(mouseleave, fermaDisegno ,false ); document.addEventListener(salvadato, salvaCanvas ); document.addEventListener(recuperadato, recuperaCanvas );}
  • 141. window.addEventListener(load ,attivaIlCanvas,false);Approfondiamo un po’ quanto scritto: la funzione appena qui sopra ‘attivaIlCanvas’ viene eseguitaal load della pagina e si preoccupa di registrare tutti gli handler necessari alla gestione delle funzionidi disegno e di registrazione. In particolare iniziaDisegno, disegna e fermaDisegno utilizzano alcunefunzioni che abbiamo esplorato nelle specifiche per disegnare delle spezzate che seguono la posizionedel mouse. salvaCanvas e recuperaCanvas sono invece funzioni che vengono attivate dai nostrieventi custom; in questo caso la parte interessante è da ricercarsi nell’utilizzo del metodo toDataUrlche trasforma il contenuto del canvas in una stringa, rendendolo quindi memorizzabile all’internodell’hash localStorage. In recuperaCanvas poi, la stessa stringa contenente l’immagine vieneutilizzata come attributo src di un oggetto Image e successivamente ridipinta sul canvas.Ricordiamoci di richiedere il file canvas.js all’interno della pagina index.html e proviamo la nostracreazione (http://www.html.it/guide/esempi/html5/esempi/lezione_canvas/fiveboard/index.html)(figura 1):Figura 1ConclusioniIl canvas è uno strumento incredibilmente vasto, potente ed articolato. La panoramica offerta daquesta lezione introduce in modo abbastanza esauriente l’insieme delle tematiche anche se per nondilungarsi troppo non ne approfondisce nessuna. Nonostante questa evidente ricchezza il canvas restacomunque uno strumento di basso livello e permane in uno stato di difficile utilizzo a meno che nonsia supportato dai dovuti framework, come ad esempio processing.js (http://processingjs.org/),canto.js (http://www.davidflanagan.com/2010/07/cantojs-an-impr.html) e l’ottimo Easel.js
  • 142. (http://easeljs.com/). In questa lezione si è inoltre volutamente ignorato il tema dell’interazione tracanvas e video, che verrà affrontato nel dovuto dettaglio nella prossima lezione di questa guida. VideoLintroduzione della possibilità di riprodurre filmati in un browser senza lausilio di plug-in di terzeparti rappresenta di per sé una grossa novità: vanno ad esaurirsi infatti tutte le tematiche legate allaproliferazione del plug-in utilizzato ed alla portabilità dello stesso (basti pensare ai mille grattacapigenerati dal connubio Flash - iOs).Ma cè molto di più! Portando il player video allinterno del DOM si sono rese disponibili tutta una seriedi interessantissime possibilità di interazione: ad esempio il tag video può essere modificatoutilizzando i CSS; lo stesso effetto può essere poi ovviamente applicato anche ai pulsanti di controllo.Inoltre lelemento espone una ricca interfaccia Javascript che ci consente di effettuare senza alcunefatica moltissime efficaci manipolazioni. Infine ricordiamo che il canvas, trattato nella lezioneprecedente, ha la facoltà di recuperare fotogrammi da un elemento video e di manipolarli; più avantimostreremo questa potente tecnica in azione.Le specifichePrima di iniziare la sperimentazione è necessario procurarsi dei video da utilizzare: per queste demoabbiamo scelto il trailer del cartone Big Buck Bunny, distribuito in licenza Creative Commons edisponibile per il download allindirizzo http://www.webmfiles.org/demo-files/(http://www.webmfiles.org/demo-files/) e dal sito ufficiale(http://www.bigbuckbunny.org/index.php/trailer-page/); lintero esempio e tutti i file necessari sonoallegati al pacchetto zip (http://www.html.it/guide/esempi/html5/esempi/esempi_html5_api.zip) checontiene tutti gli esempi della guida.Incominciamo dal markup, ecco un esempio di implementazione:<video poster="big_buck_bunny/poster.jpg" controls> <source src="big_buck_bunny/trailer.mp4" type="video/mp4" > <source src="big_buck_bunny/trailer.ogg" type="video/ogg" > <source src="big_buck_bunny/trailer.webm" type="video/webm"></video>Lattributo poster ci consente di specificare una immagine che verrà utilizzata allinterno dellarea diriproduzione prima che il video venga eseguito; controls invece indica che richiediamo la presenzadei classici controlli, come play, pausa, volume, barra di avanzamento e quantaltro. Ci sono altriattributi utilizzabili a livello di video, vediamoli: autoplay: se presente questa stringa di testo indica allo user agent di provvedere alla riproduzione del video appena si raggiungono le condizioni minime di buffer necessarie; loop: se il browser rileva questa stringa inizierà nuovamente la riproduzione del filmato una volta che questo è giunto al termine; preload: per questo attributo sono previste tre opzioni: none, metadata e auto. Con none si indica allo user-agent di non effettuare nessun download preventivo del contenuto del file video, il buffer inizierà quindi ad essere riempito alla prima pressione del tasto play; con metadata invece si richiede che vengano recuperate almeno le informazioni essenziali,
  • 143. come la durata del filmato e le sue dimensioni. Infine con auto, che è anche la valorizzazione di default, si lascia al browser totale libertà di scelta; audio: possiamo valorizzare questo attributo a muted ottenendo in questo modo che il player video non riproduca nessun suono. Nellultima versione delle specfiche la proprietà è stata sostituita da un più consono muted che deve essere valorizzato a truePassiamo a source e al grande dilemma che questi elementi sottendono: i codec. Ogni elemento diquesto tipo infatti indica al browser la disponibilità dello stesso contenuto video in formati di codificadiversi. Ad oggi non esiste un singolo codec che sia supportato dai maggiori browser in commercio: lascelta più compatibile in assoluto è il nuovissimo, e open-source, formato .webm/ vp8, che però nonè ben accetto da Safari (e quindi da iPhone et-simila), per il quale la scelta obbligata è invece ilclassico .mp4 con codifica h264. Per ogni source è necessario quindi specificare un attributo src,un type ed opzionalmente anche un codec, da valorizzare con una lista di stringhe contenente ildettaglio della codifica audio e video, separati dalla virgola.Eseguendo il primo esempio otterremo questo risultato (figura 1):Figura 1 (click per ingrandire) (http://www.html.it/guide/esempi/html5/imgs/lezione_video/1.png)Ecco la demo (http://www.html.it/guide/esempi/html5/esempi/lezione_video/video.html).Ma non è finita. Insieme agli elementi di tipo source possiamo anche specificare tag track cherappresentano vari elementi testuali che si possono combinare con il video in modi diversi.Sono un esempio di track sottotitoli, tracce, che contengono testo ed onomatopee di effetti speciali, esono di solito utilizzate dai non udenti, descrizioni, che sono invece composte da testo predisposto perla sintesi audio da parte di sintetizzatori vocali, di solito utilizzati da persone non vedenti, capitoli edaltri dati:<video poster="big_buck_bunny/poster.jpg" controls> <source src="big_buck_bunny/trailer.mp4" type="video/mp4" > <source src="big_buck_bunny/trailer.ogg" type="video/ogg" > <source src="big_buck_bunny/trailer.webm" type="video/webm"> <track kind="subtitles" src="big_buck_bunny/bunny.it.vtt" srclang="it" label="Sottotitoli in Italiano"></video>Le specifiche legate allelemento in questione non sono però, ad oggi, supportate da nessuno deiprincipali browser in commercio; la stessa estensione di file (.vtt) proposta dal W3C come standardper i sottotitoli è praticamente sconosciuta e priva di documentazione.Le APIParallelamente al markup sono state introdotte tutta una serie di API utilissime per interfacciarsi conoggetti video. Iniziamo dai più semplici, intuitivi ed utili:<!doctype html><html><head> <title>Big Buck Bunny, il trailer</title> <script> var video;
  • 144. eseguiIlPlay = function(){ video.play(); } eseguiIlPause = function(){ video.pause(); } cambiaVolume = function(evento){ video.volume = evento.target.value; } window.addEventListener(load,function(e){ video = document.querySelector(video); }) </script></head><body> <menu type="toolbar"> <button type="button" onclick="eseguiIlPlay()" > Play </button> <button type="button" onclick="eseguiIlPause()"> Pause </button> <label> Volume: </label> <input type="range" min="0.0" max="1.0" step="0.1" value="0.5" oninput="cambiaVolume(event)"> </menu> <video poster="big_buck_bunny/poster.jpg"> <source src="big_buck_bunny/trailer.mp4" type="video/mp4" > <source src="big_buck_bunny/trailer.ogg" type="video/ogg" > <source src="big_buck_bunny/trailer.webm" type="video/webm"> </video></body></html>Come potete notare, il controllo base del flusso e del volume è alquanto semplice, esistono peròalcune funzioni più particolari; ad esempio la proprietà playbackRate di un oggetto video può esserevalorizzata con cifre che indicano quale vogliamo che sia la velocità di riproduzione.Interessanti sono anche i metodi che gravitano attorno alle tematiche temporali: duration,currentTime e initialTime ritornano rispettivamente la durata in secondi del filmato, la posizionecorrente e la posizione dalla quale è partita la riproduzione (tipicamente 0). Il metodo currentTimepuò essere inoltre valorizzato causando uno spostamento della posizione del video al secondorichiesto. Ecco due funzioni che mostrano rispettivamente come raddoppiare la velocità diriproduzione e modificare la posizione corrente esattamente a metà della lunghezza del video:doppiaVelocita = function(){ video.playbackRate = 2.0;}posizionatiAlCentro = function(){ video.currentTime = Math.round(video.duration / 2);}Per attivarle aggiungiamo due pulsanti nella toolbar:<menu type="toolbar">
  • 145. ... <button type="button" onclick="doppiaVelocita()"> x2 </button> <button type="button" onclick="posizionatiAlCentro()"> Centro </button> ...</menu>Eseguiamo il codice finora prodotto per testare la bontà di quanto sviluppato (figura 2):Figura 2 (click per ingrandire)(http://www.html.it/guide/esempi/html5/imgs/lezione_video/2.png)Lultima parte del capitolo riguardante le API di questo elemento è dedicata ad una classeinteressante denominata TimeRanges e composta da un attributo: length e due metodi start(n) eend(n). Alcuni metodi dellelemento video ritornano oggetti di questo tipo che contengonoinformazioni in merito a collezioni di intervalli temporali; ecco un esempio (aggiungiamolo alla demoprecedente):generaTesto = function(intervalli){ var testo = "Ci sono: " + intervalli.length + " intervalli"; for(var i=0; i < intervalli.length; i++){ testo +="ntda: " + intervalli.start(i) + " a:" + intervalli.end(i) + " secondi" } return testo;}ottieniInformazioni = function(){ var caricato = video.buffered; var riprodotto = video.played; var ricercabile = video.seekable;
  • 146. alert( "Alcune informazioni sul video n" + "= Caricato =n" + generaTesto(caricato) + "n" + "= Riprodotto =n" + generaTesto(riprodotto) + "n" + "= Ricercabile =n" + generaTesto(ricercabile) );}Creiamo il bottone corrispondente, lanciamo la demo e sinceriamoci delleffettivo funzionamento:<button type="button" onclick="ottieniInformazioni()"> Info </button>Nello screenshot in figura 3 possiamo verificare il risultato:Figura 3 (click per ingrandire)(http://www.html.it/guide/esempi/html5/imgs/lezione_video/3.png)Anche in questo caso è disponibile una demo(http://www.html.it/guide/esempi/html5/esempi/lezione_video/video_api_1.html).Gli eventiLelemento video comunica attraverso un elenco lunghissimo di eventi, i principali sono facili efacilmente comprensibili, come ad esempio play, playing, pause e waiting; per la lista completarimandiamo alle specifiche W3C (http://dev.w3.org/html5/spec/Overview.html#mediaevents).MediaController APISolo un piccolo accenno ad un set di API di recentissima pubblicazione; grazie alle MediaControllerAPI e con lausilio di un nuovo attibuto mediagroup, disponibile sia per elementi audio che video, è
  • 147. possibile chiedere allo user agent di gestire la riproduzione di più oggetti multimediali in modosincronizzato. Facciamo un esempio:<video poster="big_buck_bunny/poster.jpg" controls mediagroup="anteprime"> <source src="big_buck_bunny/trailer.mp4" type="video/mp4" > <source src="big_buck_bunny/trailer.ogg" type="video/ogg" > <source src="big_buck_bunny/trailer.webm" type="video/webm"></video><video poster="big_buck_bunny/poster.jpg" controls mediagroup="anteprime"> <source src="mixer/movies/src/ballo_green_screen.mp4" type="video/mp4" > <source src="mixer/movies/src/ballo_green_screen.ogg" type="video/ogg" > <source src="mixer/movies/src/ballo_green_screen.webm" type="video/webm"></video>in questo caso, avendo lo stesso valore per lattributo mediagroup, entrambi i video vengono associatiallo stesso oggetto di tipo MediaController generato a runtime dal browser. Questo oggetto diventaquindi responsabile della gestione temporale dei due filmati e ne coordina la riproduzione in sincrono.Per accedere a questo oggetto la sintassi è estremamente semplice:// ritorna il MediaController associato al video, se presentedocument.querySelector("video").controllercosì come semplici sono i metodi e gli eventi disponibili in quanto coincidono quasi completamentecon quelli dei MediaElements (es: play, pause, volume e tutto quanto visto in questa lezione).Purtroppo nessun browser ad oggi implementa questo promettente set di API ma, visto linteresse sultema, lattesa non dovrebbe rivelarsi troppo lunga. Video e Canvas: un esempio praticoIn questa lezione vedremo come manipolare flussi video in tempo reale con lausilio di un canvas.Perché il tutto funzioni è necessario che sia il video che la pagina che costruiremo risiedano sullostesso dominio. Questo per prevenire lintervento di alcune policy di sicurezza del browser cheimpediscono di fatto la modifica di materiale multimediale che non provenga dalla stessa origine dellapagina. Ecco uno schema di quanto realizzeremo:Figura 4 (click per ingrandire)
  • 148. (http://www.html.it/guide/esempi/html5/imgs/lezione_video/4.png)Utilizzeremo due canvas. Nel primo replicheremo i fotogrammi del video, mentre nel secondoandremo a inserire il risultato della nostra elaborazione sullarray di pixel estratti dal primo. Ilprocedimento sarà quindi il seguente: Avviare la riproduzione del video; Utilizzare la funzione drawImage per disegnare sul primo canvas il contenuto del fotogramma corrente del video; Con la funzione getImageData recuperare dal canvas il fotogramma precedentemente disegnato, questa volta però come array di pixel modificabili; Effettuare un ciclo su tutti i pixel recuperati apportando le modifiche volute; Utilizzare la funzione putImageData per disegnare larray di pixel modificato sul secondo canvas; Ripetere dal secondo punto la procedura.Ecco il codice necessario:<!doctype html><html><head> <title> Canvas e Video </title> <script> decomposizioneColori = function(video, context, context_nascosto, colori){ if(video.paused || video.ended) return false; context_nascosto.drawImage(video,0,0); var fotogramma = context_nascosto.getImageData(0,0, context_nascosto.canvas.width,context_nascosto.canvas.height); var fotogramma_data = fotogramma.data; var rosso = colori.rosso.checked; var verde = colori.verde.checked; var blu = colori.blu.checked;
  • 149. for(var i=0; i < fotogramma_data.length; i+=4){ if (!rosso) fotogramma_data[i ] = 0; if (!verde) fotogramma_data[i+1] = 0; if (!blu ) fotogramma_data[i+2] = 0; } fotogramma.data = fotogramma_data; context.putImageData(fotogramma,0,0); setTimeout(function(){ decomposizioneColori(video, context, context_nascosto, colori) },0); } aspettaIlPlay = function(evento){ var video = document.querySelector(video); video.addEventListener("play", function(evento){ var context = document.querySelector(#canvas_principale).getContext(2d); var context_nascosto = document.querySelector(#canvas_elaborazione).getContext(2d); context.canvas.width = context_nascosto.canvas.width = video.clientWidth; context.canvas.height = context_nascosto.canvas.height = video.clientHeight; decomposizioneColori(evento.target,context,context_nascosto, document.forms.colori); },true); } window.addEventListener("load",aspettaIlPlay,true); </script></head><body> <canvas id="canvas_principale"></canvas> <canvas id="canvas_elaborazione" style="display:none;"></canvas> <video poster="big_buck_bunny/poster.jpg" controls> <source src="big_buck_bunny/trailer.mp4" type="video/mp4" > <source src="big_buck_bunny/trailer.ogg" type="video/ogg" > <source src="big_buck_bunny/trailer.webm" type="video/webm"> </video> <form name="colori"> <fieldset> <legend>Usa le checkbox per controllare i tre canali (RGB)</legend> <label> Rosso <input type="checkbox" name="rosso" checked></label> <label> Verde <input type="checkbox" name="verde" checked></label> <label> Blue <input type="checkbox" name="blu" checked></label> </fieldset> </form></body></html>
  • 150. Il funzionamento si concentra in decomposizioneColori; qui vengono eseguite tutte le operazioniche abbiamo citato. Allinterno del ciclo che scorre tutti i pixel (nelle componenti RGBA) un semplicecontrollo pilotato da una form spegne le componenti di colore corrispondenti ad una checkbox nonspuntata con un risultato simile a quello dellimmagine seguente:Figura 5Merita un cenno anche linteressante uso della funzione requestAnimationFrame(http://www.w3.org/TR/animation-timing/); il W3C ha predisposto questo metodo per megliocoordinare la gestione di animazioni allinterno di documenti web. A differenza dei suoi cuginisetTimeout e setInterval questa funzione applica alcune tecniche per ottimizzare le perfomance emantenere basso lutilizzo delle risorse del sistema. Purtroppo la maggior parte dei browser laconsidera ancora sperimentale e quindi antepone il proprio prefisso (moz, o, ms o webkit). Perrisolvere questo problema esistono alcuni snippet di codice come quello proposto da Paul Irish
  • 151. (http://paulirish.com/2011/requestanimationframe-for-smart-animating/).Possiamo verificare il tutto nella demo conclusiva(http://www.html.it/guide/esempi/html5/esempi/lezione_video/video_canvas.html).ConclusioniIn queste ultime due lezioni abbiamo esplorato tutto lecosistema che circonda la nascita del tagvideo. Prima di passare alla prossima lezione ricordiamo che intorno a questo elemento già siaffacciano le prime librerie, capaci di aiutare nella personalizzazione del player e nella gestione difallback su altre tecnologie nel caso lHTML5 non sia supportato. In particolare segnaliamo lottimovideo.js (http://videojs.com/), che sicuramente merita una visita di approfondimento. AudioLa presenza del tag audio è naturale conseguenza dellesistenza di video(http://xhtml.html.it/guide_preview/lezione/5003/video/). Fra laltro i due elementi si assomiglianomolto, sia in materia di markup che di API, al punto che nelle specifiche sono raggruppati allinternodella definizione di HTML Media Elements. Lutilizzo del tag audio sottende però aspettiassolutamente originali ed interessanti; soprattutto quando utilizzato per arricchire con effetti sonoriuna struttura HTML classica.Le specificheLa rappresentazione a markup dellelemento ricalca perfettamente quella del video, anche se vi sonomeno attributi disponibili, vediamo un esempio:<audio controls autoplay loop src="file_musicale.mp3">In questo caso la definizione si risolve su di una singola linea e senza utilizzo del tag source perché èstato utilizzato lattributo src, il cui compito è quello di evitare una scrittura troppo prolissa nel casoin cui il formato disponibile sia unico. Questo attributo anche se non è stato presentato nella lezioneprecedente è valido anche per il tag video, anche se a meno di un reale processo di unificazione deicodec ad oggi perde molta della sua utilità. In ogni caso la stessa definizione appena espressa si puòscrivere anche nel formato esteso:<audio controls autoplay loop> <source src="file_musicale.mp3" type="audio/mp3"></audio>Oltre agli attributi presentati nel codice qui sopra, deve essere citato anche preload; ognuno diquesti è già stato illustrato nella lezione precedente e mantiene intatto il suo funzionamento anche suquesto elemento. A differenza di video, lelemento audio dispone anche di un proprio costruttoreJavaScript, ecco la sintassi:var audio = new Audio("file_musicale.mp3");In questo modo è possibile utilizzare musiche ed effetti audio senza necessariamente creare
  • 152. lelemento HTML né ricorrere a display:none o similari; tratteremo più approfonditamente di questoaspetto nella sezione dedicata allesempio.Per quanto riguarda invece le API e gli eventi associati a questo elemento lelenco è pressochécongruente con quello dellelemento video; le stesse funzioni play, pause, playbackRate,duration,currentTime e tutto quanto legato ai TimeRanges mantengono inalterato il propriocomportamento in quanto appartenenti al gruppo HTMLMediaElements al quale entrambi gli elementifanno parte.Un esempioSfruttiamo la possibilità di creare oggetti audio utilizzando il costruttore JavaScript per studiare unmeccanismo che ci consenta di associare ad ogni bottone un suono predefinito da riprodurre al click.Ecco il markup che useremo allinterno del body della pagina:<button type="button" data-effetto-audio="gatto_che_miagola.mp3" disabled> Il verso del gatto...</button><button type="button" data-effetto-audio="cane_che_abbaia.mp3" disabled> Il verso del cane...</button>Lutilizzo degli attributi data-* ci consente in modo elegante di aggiungere uninformazionecaratterizzante al pulsante, senza creare strane sovrastrutture. Ora il codice JavaScript dovràoccuparsi di scandagliare la pagina alla ricerca di pulsanti con suono associato e creare un oggettoaudio con la sorgente che punti allattributo che abbiamo definito. Levento canplaythrough, verràutilizzato per intercettare il momento in cui un dato oggetto audio ritiene di aver collezionato datisufficienti per garantire la riproduzione dellintero brano. Allaccadere di tale evento il pulsanteassociato al suono verrà abilitato e un listener in ascolto sullevento click garantirà lesecuzione delsuono alla pressione del bottone. Ecco il codice della demo completa:<!doctype html><html><head> <title>Il suono degli animali</title> <script> init = function(evento){ var bottoni = document.querySelectorAll(button); for(var b=0; b < bottoni.length; b ++){ var effetto_audio = bottoni[b].dataset.effettoAudio; if(effetto_audio != ""){ var audio = new Audio(effetto_audio); audio.bottone_di_riferimento = bottoni[b]; audio.addEventListener(canplaythrough, function(evento_load){ var bottone = evento_load.target.bottone_di_riferimento; bottone.disabled = false; bottone.audio_di_riferimento = evento_load.target; bottone.addEventListener(click, function(evento_click){ evento_click.target.audio_di_riferimento.play(); }
  • 153. ); } ); } } }window.addEventListener(load,init); </script></head><body><button type="button" data-effetto-audio="gatto_che_miagola.mp3" disabled>Il verso del gatto...</button><button type="button" data-effetto-audio="cane_che_abbaia.mp3" disabled>Il verso del cane...</button></body></html>Il codice sembra a prima vista complicato ma è facilmente decomponibile in 3 fasi principali: Un ciclo for viene eseguito al caricamento della pagina su tutti gli elementi di tipo button; per ognuno di questi elementi viene istanziato un oggetto Audio. Su tale oggetto viene memorizzato un riferimento al bottone associato tramite la variabile bottone_di_riferimento e viene registrato un handler sullevento canplaythrough. Quando un oggetto Audio colleziona un buffer di dati ritenuto dal browser tale da consentire la riproduzione integrale del suono, levento canplaythrough viene lanciato ed intercettato dalla nostra funzione che a quel punto crea, con un meccanismo simile al punto precedente, un handler sul pulsante presente nella variabile bottone_di_riferimento da attivarsi alla pressione dello stesso. Inoltre il pulsante viene abilitato (bottone.disabled=false) in modo da poter ricevere i click degli utenti. Il click dellutente su di un pulsante attiva lhandler appena definito che non fa altro che riprodurre il suono presente nelloggetto Audio ad esso associato.Eseguiamo lapplicazione appena sviluppata e sinceriamoci del suo corretto funzionamento: eccolesempio (http://www.html.it/guide/esempi/html5/esempi/lezione_audio/audio.html).ConclusioniLelemento che abbiamo illustrato in questa sezione corre di pari passo con limplementazione HTML5del video, dal quale, abbiamo visto, eredita pressoché la totalità delle proprietà. Nonostante questolutilizzo dellelemento audio si presta a scenari molto più variegati rispetto a quanto ci si potrebbeimmaginare: parte di questa interessante flessibilità risiede proprio nella sua predisposizione adessere creato direttamente da JavaScript.Tabella del supporto sui browserGrafica e Multimedia<audio> 9.0+ 3.5+ 4.0+ 5.0+ 10.5+Codec audio
  • 154. MP3 Sì No Sì Sì NoWav No Sì Sì No SìAAC Sì No Sì Sì NoOgg/Vorbis No Sì No Sì Sì SVG e MathMLSVGSVG è un acronimo che significa Scalable Vector Graphic e indica una specifica modalità di definireelementi di natura grafica attraverso una sintassi XML, ecco un esempio:<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="300px" height="300px" viewbox="0 0 300 300" xmlns="http://www.w3.org/2000/svg" version="1.1"> <title>Una barchetta in SVG</title> <desc>La stessa barchetta della lezione sui canvas ora in SVG</desc> <path d="M40,170 h220 A150,150 0 0,1 40,170 h110 v-130 v130 h-110 z" fill="black" stroke="black" stroke-width="1"/> <rect x="150" y="40" width="60" height="30" fill="black" stroke="black" stroke-width="1"/></svg>La maggior parte dei browser in circolazione interpreta correttamente lo standard SVG, se proviamo avisualizzare questa pagina(http://www.html.it/guide/esempi/html5/esempi/lezione_svg/barchetta.svg) in Chrome otterremoquesto risultato (figura 1):Figura 1Nonostante il risultato sia a prima vista identico rispetto alla barchetta disegnata all’interno dellalezione sull’elemento canvas, si può notare come a livello di codice ci sia una enorme differenza:mentre sul canvas è necessario insistere con istruzioni JavaScript che pilotano la creazione deldisegno, qui ci troviamo di fronte ad un linguaggio XML fatto per descrivere l’immagine. Ma non èfinita: da un lato (canvas) stiamo lavorando su di una matrice di pixel, che quindi non può essereridimensionata senza subire perdite di qualità; dall’altro, con SVG, operiamo con grafica vettoriale,che preserva in modo assoluto lo stesso risultato a prescindere dalle operazioni di trasformazioneapplicate ad essa.MathMLAnche MathML è un acronimo: Mathematical Markup Language; il fine di questa sintassi è quellodi rendere possibile la visualizzazione a schermo di formule complesse, senza ricorrere al
  • 155. classico espediente dell’utilizzo di immagini create a partire da screenshot di applicazioni scientifiche.Anche in questo caso stiamo parlando di sintassi XML-like. A seguire un esempio della famosaequazione di Einstein secondo queste specifiche:<?xml version="1.0" encoding="UTF-8"?><math xmlns="http://www.w3.org/1998/Math/MathML"> <semantics> <mrow> <mi>E</mi> <mi mathvariant="normal">=</mi> <msup> <mi mathvariant="italic">mc</mi> <mn>2</mn> </msup> </mrow> <annotation>E=mc^2</annotation> </semantics></math>Per testare la sintassi del nostro esempio(http://www.html.it/guide/esempi/html5/esempi/lezione_svg/emc2.mml.html) è necessario munirsidella versione nightly (sperimentale) del browser WebKit (http://nightly.webkit.org/), tra i pochi asupportare queste specifiche. Questo è il risultato (figura 2):Figura 2Novità in HTML5Ed ecco la novità: le specifiche HTML5 prevedono l’integrazione di entrambi questi markup senzanessuna definizione aggiuntiva (a differenza della precedente integrazione con XHTML). Sarà quindipossibile scrivere:<!doctype html><html>
  • 156. <title>Big Buck Bunny, il trailer</title><body> <svg> <!-- elementi SVG --> </svg> <math> <!-- elementi MathML --> </math></body></html>E c’è di più: le due sintassi in questione potranno direttamente beneficiare dell’intero ecosistemaHTML5 attorno a loro. Questo significa che una espressione MathML può, in questo contesto, variare aseguito della ricezione di alcuni dati tramite Ajax, oppure che una rappresentazione SVG può esserepilotata da alcuni eventi JavaScript attivati attraverso una form.ConclusioniCon queste due nuove frecce al suo arco, le specifiche HTML5 acquistano un nuovo livello di potenza.Forse non capiterà troppo spesso di implementare sintassi MathML per sistemi applicativi masicuramente lo stesso non si può dire per SVG. Anche il supporto a queste due specifiche è diverso, laScalable Vector Graphic è pressoché presente su tutte le più recenti versioni dei browser, mentre ilsupporto per il markup per definire espressioni matematiche comincia ora ad affacciarsi nelle primebeta, come ad esempio Firefox 4 o la versione nightly di WebKit. In ogni caso esiste una interessantelibreria JavaScript, MathJax (http://www.mathjax.org/), capace di interpretare linguaggio MathML egenerare una corretta rappresentazione grafica sulla maggior parte dei browser in commercio. Una lavagna virtualeNel corso delle lezioni abbiamo assistito al graduale arricchimento del progetto guida; in questoarticolo ne esploreremo alcune possibili evoluzioni attraverso l’utilizzo delle API HTML5 apprese finora.Il canvas nella dashboardÈ possibile fare in modo che dalla dashboard (dashboard.html) si possa visualizzare il contenuto,attuale e salvato, del canvas di una data fiveboard con un meccanismo simile a quello utilizzato per lamemorizzazione su localStorage. Per ottenere questo risultato possiamo sostituire il blocco legato alcomando ‘richiedi_testo’ nel file application.js con:case richiedi_testo: evento.ports[0].postMessage(testo_corrente: + document.forms[form_da_ricordare].elements[testo_da_ricordare].value); evento.ports[0].postMessage(testo_memorizzato: + localStorage.getItem("fb_" + titolo_fiveboard)); evento.ports[0].postMessage(canvas_corrente: + ctx.canvas.toDataURL(image/png)); evento.ports[0].postMessage(canvas_memorizzato:+
  • 157. localStorage.getItem("canvas_fb_" + titolo_fiveboard));break;A questo punto dobbiamo far sì che la dashboard sappia ricevere ed interpretare correttamente questi4 distinti messaggi, modifichiamo quindi il blocco che fa seguito al comando attendi_testo indashboard.html:case attendi_testo: evento.ports[0].onmessage = function(e){ nome_comando = e.data.split(":")[0] valore_comando = e.data.substr(nome_comando.length + 1); elemento = document.getElementById(nome_comando); switch (elemento.tagName){ case CANVAS: elemento.width = elemento.width; if(valore_comando == null) return var context = elemento.getContext(2d); var immagine = new Image(); immagine.src = valore_comando; context.drawImage(immagine,0,0); break; case TEXTAREA: if(valore_comando == null) valore_comando = ; elemento.value = valore_comando; break; } }break;Nel frammento di codice appena esposto facciamo uso dell’attributo tagName per determinare il tipo dielemento che deve contenere le informazioni appena ricevute. In questo modo il comando‘testo_memorizzato:contenuto_del_testo’ inviato dalla fiveboard si traduce nella valorizzazionedell’elemento ‘testo_memorizzato’ a ‘contenuto_del_testo’ nella dashboard.Completiamo questa evoluzione inserendo gli elementi di markup all’interno di dashboard.html:</ol><section> <h1>In Osservazione:</h1> <textarea id="testo_corrente" placeholder="testo_corrente" readonly></textarea> <textarea id="testo_memorizzato" placeholder="testo_memorizzato" readonly></textarea> <canvas id="canvas_corrente">Canvas Corrente</canvas> <canvas id="canvas_memorizzato">Canvas Memorizzato</canvas></section>Ecco uno screenshot dell’implementazione funzionante (figura 1):
  • 158. Figura 1 (click per ingrandire)(http://www.html.it/guide/esempi/html5/imgs/lezione_progetto/1.jpg)Com’è possibile notare, ora alla pressione sul link ‘più informazioni’ la dashboard è in grado dimostrare sia testo che canvas, attuali e memorizzati, della fiveboard richiesta.Esportazione in SVGPotrebbe essere interessante, in questo contesto, offrire ai nostri utenti una esportazione in SVG delcontenuto del canvas. In un prossimo futuro il task in questione potrà essere risolto in modo efficaceutilizzando la funzione canvas.toDataUrl con parametro ‘image/svg+xml’ ; purtroppo ad oggi ibrowser supportano soltanto unesportazione in formato png e quindi dovremo costruire qualcosa dipiù articolato per soddisfare questo comportamento.
  • 159. Iniziamo con l’aggiungere questa funzione in canvas.js:EsportaInSVG = function(){ var bb = new BlobBuilder(); bb.append( "" + "<?xml version=1.0 standalone=no?>" + "<!DOCTYPE svg PUBLIC -//W3C//DTD SVG 1.1//EN" + " http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd>" + "<svg width=300px height=300px viewbox=0 0 300 300" + " xmlns=http://www.w3.org/2000/svg version=1.1>" + " <title>SVG: " + titolo_fiveboard + "</title>" + " <desc>Un esportazione in SVG del canvas disegnato</desc>" + " <path d=" + svg_path + " z fill=transparent" + " stroke=black stroke-width=1/>" + "</svg>" ); window.open(window.createObjectURL(bb.getBlob(image/svg+xml)));}L’oggetto BlobBuilder fa parte delle File API: Writer (http://www.w3.org/TR/file-writer-api/), un setdi funzionalità che gravitano attorno alle specifiche HTML5 e consentono di costruire veri e propri fileda far scaricare all’utente o ai quali far puntare il browser. Al momento questi metodi sono ancoraabbastanza sperimentali, nonostante già supportati in Chrome, Firefox e WebKit. In questo esempiola variabile bbviene valorizzata con un file SVG nel quale sono inseriti dinamicamente i contenuti dellevariabili titolo_fiveboard, il titolo della fiveboard, e svg_path, della cui costruzione ci occuperemoa breve. Nell’ultima riga della funzione il browser apre una nuova finestra verso una URL univocagenerata dal metodo createObjectURL. Tale URL punta al contenuto della variabile bb esposto conMIME image/svg+xml.Occupiamoci ora della generazione della variabile svg_path che dovrà contenere le istruzioni perricostruire il percorso generato dall’utente sul canvas. Modifichiamo il file canvas.js come segue:var ctx = null;var started = false;var svg_path = "";iniziaDisegno = function(evento){ ctx.beginPath(); ctx.moveTo(evento.offsetX,evento.offsetY); svg_path += "M " + evento.offsetX + " " + evento.offsetY + " "; started = true;}disegna = function(evento){ if(started){ ctx.lineTo(evento.offsetX,evento.offsetY); svg_path += "L " + evento.offsetX + " " + evento.offsetY + " "; ctx.stroke(); }}
  • 160. Il trucco sta nel far seguire all’istruzione che insiste sul canvas la corrispondente variazione daapplicare al path svg. In questo modo una particella ‘M x y’ verrà concatenata a svg_path per ogniistruzionemoveTo inviata al canvas, lo stesso accadrà per l’istruzione lineTo, seguita da unaconcatenazione di ‘L x y’.L’ultimo passo prima del completamento di questa evoluzione consiste nell’aggiungere il pulsantepreposto a far scatenare la funzione EsportaInSVG: </button> <button type="button" onclick="EsportaInSVG();"> Esporta il canvas corrente in SVG </button></menu>Per testare questa modifica ricorriamo a Chrome (figura 2):Figura 2 (click per ingrandire)(http://www.html.it/guide/esempi/html5/imgs/lezione_progetto/2.jpg)
  • 161. Ed ecco il risultato! Mentre la barchetta nella finestra in sfondo risiede su di un canvas quella in primopiano è creata a partire da un file SVG; notate inoltra il curioso URL di questa finestra, generato intempo reale dalla funzione di cui abbiamo parlato poco fa.Non ci resta che rimandare alla demo(http://www.html.it/guide/esempi/html5/esempi/lezione_progetto/fiveboard/index.html) per un test.Il codice è disponibile per il download(http://www.html.it/guide/esempi/html5/esempi/lezione_progetto/fiveboard.zip).Un passo avantiCon quest’ultima evoluzione ci apprestiamo a congedare il progetto guida, utile assistente durante lepassate lezioni. Per chi fosse interessato a mantenere questo applicativo come base per propriesperimentazioni ecco alcuni possibili e sfidanti implementazioni effettuabili: Fare in modo che il viewer.html possa seguire in tempo reale anche l’atto del disegno sul canvas della fiveboard che sta osservando, così come oggi avviene per il testo. Questa modifica coinvolge la definizione di un protocollo snello per la trasmissione di dati di questo tipo attraverso un WebSocket. Refactoring! Perché non provare a fare in modo che i comandi che giungono alle pagine web nel formato scelto per convenzione come ‘nome_comando:valore_comando’ siano trasformati in eventi custom e propagati attraverso il DOM ? La sintassi potrebbe essere questa:worker.port.onmessage = function(evento){ nome_comando = evento.data.split(":")[0] valore_comando = evento.data.substr(nome_comando.length + 1); var evento_custom = document.createEvent("CustomEvent"); evento_custom.initCustomEvent(nome_comando, true, true, valore_comando); document.dispatchEvent(evento_custom);}In questo modo si potrebbe ottenere una struttura molto più elegante, nella quale ogni aspettodell’applicazione si sottoscrive autonomamente agli eventi dei quali necessita.ConclusioniCon questa lezione si conclude il ciclo dedicato all’esplorazione delle nuove API rese disponibilidall’HTML5. Prima della conclusione di questa guida trova spazio unultima lezione, la prossima,incentrata su tutte le tematiche che legano le specifiche al mondo reale. Verranno quindi trattati temicome il feature detection ed elencate librerie che possono, di caso in caso, sopperire alla mancanzadi particolari funzionalità. Proprio a questo tema ricordiamo che il progetto guida è nato e cresciutocon finalità didattiche e di sperimentazione e per questa ragione è molto carente in termini dicompatibilità tra browser e graceful degradation; a ben pensare anche perseguire queste tematichepotrebbe essere un ottimo esercizio da svolgere in autonomia dopo aver letto la prossima lezione! Feature detection e strategie di fallbackCome si comportano le API e i nuovi tag proposti dallHTML5 nel mondo reale? Come dobbiamo
  • 162. comportarci se vogliamo beneficiarne? In questultima lezione risponderemo a questa importantissimadomanda esaminando alcune best-practice per una implementazione che possa arricchire le nostreapplicazioni e portali web senza causare grattacapi e disagi.Una pioggia di tagPossiamo usare <article>, <section> o <footer> su browser come Internet Explorer 6? Larisposta è sì, a patto di premunirsi di alcuni semplici e comodi strumenti capaci di far recepire questinuovi elementi HTML5 anche a user-agent non più giovanissimi. Uno di questi tool, specificatamenteprogettato per i browser di casa Microsoft, prende il nome di html5shim(http://code.google.com/p/html5shim/) e può essere incluso nelle proprie applicazioni moltofacilmente:<!--[if lt IE 9]><script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script><![endif]-->Questo strumento fa sì che Internet Explorer possa applicare gli stili ai nuovi tag introdottidallHTML5. Ma ancora non basta. La maggior parte dei browser di non ultima generazione, infatti,non conoscendo direttamente i nuovi elementi, applica a loro un foglio di stile di base errato,assegnando ad esempio display:inline a tag come <article> o <section>.Per risolvere questa fastidiosa incombenza la soluzione migliore è utilizzare un foglio di stile capace diresettare le proprietà di questi e altri elementi attivando il comportamento atteso. HTML5 resetstylesheet (http://html5doctor.com/html-5-reset-stylesheet/) si presta in modo ottimale a questoobiettivo; lunico passo da compiere è includerlo allinterno del proprio sito prima degli altri documenti.css.Feature detection vs. browser detectionLa corsa allHTML5 intrapresa dai vari browser nellultimo periodo si può descrivere come unaincrementale implementazione delle feature proposte dal W3C; il criterio con cui viene stabilita lapriorità nella scaletta delle API da aggiungere è influenzato da moltissimi fattori e differisce daprodotto a prodotto. Allo stato attuale delle cose non ha quindi particolarmente senso determinare ilcomportamento della propria applicazione sulla base dello user-agent che la sta eseguendo, quantopiù cercare di intercettare la presenza o meno di una specifica feature.Lattività, potenzialmente noiosa di per sé, viene facilitata in modo estremo dalla presenza sulmercato di un utilissimo tool: Modernizr.js (http://www.modernizr.com/). Facciamo un esempio,sinceriamoci del supporto per il localStorage:if(Modernizr.localstorage) { alert("Rilevato il supporto per il localStorage");} else { alert("Oh oh, nessun supporto per il localStorage");}Semplice, elegante e molto comodo. Linstallazione di questa libreria si risolve con una sempliceinclusione e una speciale classe da applicare al tag <html>:<html class="no-js"><head>
  • 163. <script src="/modernizr-1.6.min.js"></script> <script> // Ora puoi utilizzare Modernizr! </script></head>Fallback e alternativeAbbiamo scoperto che il nostro utente non supporta una certa funzionalità... e ora? Niente panico:nella maggior parte dei casi esistono valide alternative, o quantomeno interessanti opzioni difallback. Vediamole nel dettaglio.Audio e VideoIn questo caso lalternativa migliore rimane la collaudata tecnologia Flash. Esistono parecchielibrerie sulla rete capaci di determinare autonomamente il supporto o meno al tag <video> e agire diconseguenza. Noi abbiamo scelto video.js (http://videojs.com/) per la sua maturità e per lottimosupporto di skin con le quali personalizzare il proprio player. Lutilizzo è semplicissimo e ben illustratonella pagina di Getting Started (http://videojs.com/#getting-started).CanvasAbbiamo due soluzioni da segnalare come alternativa allassenza canvas: la prima si chiamaexplorercanvas (http://code.google.com/p/explorercanvas/), una libreria Javascript sviluppata daGoogle per simulare il comportamento del <canvas> allinterno di Internet Explorer. Per attivarla èsufficiente richiamare lo script excanvas.js allinterno del proprio tag <head>:<!--[if IE]><script src="excanvas.js"></script><![endif]-->Da qui in poi è possibile utilizzare allinterno della pagina il tag <canvas> ed invocare su questo lamaggior parte dei metodi previsti dalle specifiche W3C.Laltra tecnica di fallback prende invece il nome di FlashCanvas (http://flashcanvas.net/) ed emula ilcomportamento delle API HTML5 attraverso il sapiente utilizzo della tecnologia Flash. La versione 1.5,supera più del 70% dei test proposti da Philip Taylor(http://philip.html5.org/tests/canvas/suite/tests/), piazzandosi in questo modo sul primo gradino delpodio delle alternative disponibili. Anche in questo caso per beneficiare di questa libreria è necessariosolamente richiamare lapposito file javascript:<!--[if lt IE 9]><script type="text/javascript" src="path/to/flashcanvas.js"></script><![endif]-->GeolocationCome simulare le API di geolocazione quando non sono supportate? Prima di disperare è importantericordare che seppur non tutti browser implementano queste specifiche è comunque possibile allevolte accedere ad informazioni geospaziali utilizzando API proprietarie messe a disposizione daparticolari device o plug-in esterni, come ad esempio Google Gears. geo-location-javascript(http://code.google.com/p/geo-location-javascript/) è una libreria che identifica le varie estensionidisponibili sul portatile (o smartphone) dellutente e ne uniforma e centralizza le API permettendo di
  • 164. accedere ad informazioni come latitudine e longitudine usando gli stessi metodi proposti dal W3C.Ecco un esempio. Per prima cosa è necessario includere i necessari file javascript:<script src="http://code.google.com/apis/gears/gears_init.js" type="text/javascript"></script><script src="geo.js" type="text/javascript" ></script>Quindi è necessario inizializzare la libreria con il comando:if (!geo_position_js.init()) { // funzionalità di geolocazione non presenti (ne HTML5 ne attraverso estensioni // proprietarie...)}A questo punto è possibile invocare i classici metodi come da specifiche W3C, stando attendi apreporre loggetto geo_position_js:geo_position_js.getCurrentPosition(funzione_se_successo,funzione_se_errore);Drag and DropIn questo caso ci sono due tematiche da affrontare: la prima è di carattere workaround e si focalizzasullidentificare soluzioni alternative che preservino lo stesso meccanismo di interazione del Drag andDrop HTML5. Per questo tipo di eventualità esistono potentissime librerie capaci di offrire esattamentequesto tipo di comportamento: le più famose sono ovviamente JQueryUI(http://jqueryui.com/demos/draggable/), ma anche Scriptaculous(http://madrobby.github.com/scriptaculous/draggable/) e il nuovo Scripty2(http://scripty2.com/doc/scripty2%20ui/s2/ui/behavior/drag.html). Tutto questa interazione difallback, invece, viene meno nel caso le API previste dal W3C siano utilizzate espressamente per laloro funzione di input, quindi, ad esempio, per trascinare file allinterno della pagina web. In questocaso si può pensare di mantenere la funzionalità riducendo il potere dellinterfaccia e dellinterazione,realisticamente con lutilizzo di normalissime form e di campi <input type=file>.WebSocketAppurata lassenza del supporto WebSocket lalternativa migliore rimane ripiegare su una tra letecniche per soppiantare le quali sono nate proprio queste API HTML5: stiamo parlando di Comet ediwebsocket in Flash. Proprio a proposito di questultima opzione merita un cenno lottimo, anchese poco documentato, web-socket-js (https://github.com/gimite/web-socket-js/blob/master/README.txt) capace di replicare il comportamento delle specifiche W3C utilizzandoperò un piccolo componente Flash iniettato dinamicamente allinterno della pagina. A questo indirizzo(https://github.com/gimite/web-socket-js/blob/master/sample.html) un esempio di utilizzo.WebWorkersNon esistono, al momento, soluzioni di ripiego per riparare lassenza del supporto di questa partedelle specifiche HTML5 senza ricorrere ad estensioni di terze parti come le ottime WorkerPool API(http://code.google.com/intl/it-IT/apis/gears/api_workerpool.html) di Google Gears. Lunicoworkaround possibile è scrivere una versione del codice eseguito dal worker capace di funzionareallinterno del contesto della pagina ed eseguire quella nel caso in cui venga verificata lassenza dellafeature (chiaramente perdendo il vantaggio dellesecuzione asincrona). Nel caso invece si stia
  • 165. trattando si SharedWebWorkers il discorso si complica ulteriormente; è in linea teorica possibileemulare artigianalmente un comportamento di questo tipo utilizzando un area di storage comune (es:localStorage) per lo scambio di messaggi convenzionati tra le pagine dello stesso dominio.WebStorage e IndexedDBCome per i WebWorkers, anche qui la soluzione di fallback più completa in termini di funzionalitàpassa attraverso Google Gears: stiamo parlando delle Database API (http://code.google.com/intl/it-IT/apis/gears/api_database.html). E però importante sottolineare che, mentre WebStorage eIndexedDB basano la loro filosofia di funzionamento su array associativi, Google Gears si appoggia aduna istanza di SQLite, un database relazionale che opera tramite classiche istruzioni SQL, In questocaso quindi offrire una soluzione alternativa allassenza di questi componenti HTML5 potrebbe rivelarsidecisamente costoso.Offline Web ApplicationGoogle Gears anche in questo caso. Le API si chiamano LocalServer (http://code.google.com/intl/it-IT/apis/gears/api_localserver.html) e presentano funzionalità simili a quelle offerte dalleimplementazioni delle specifiche W3C.Shim e Polyfill a profusioneAbbiamo dato solo un piccolo assaggio della quantità di librerie alternative disponibili per sopperirealle più svariate API HTML5. In realtà il numero di questi software di fallback è decisamentesostanzioso ed è bene introdurre alcune differenze di massima tra le varie tipologie di libreriedisponibili.Definiamo come Shim una libreria che sopperisce ad una funzione mancante emulandone ilcomportamento ma richiedendo allo sviluppatore uno sforzo aggiuntivo in quando le API che mette adisposizione differiscono da quelle native in HTML5. Con Polyfill indichiamo invece uno Shim che peròfornisce allo sviluppatore le medesime API offerte dalla controparte HTML5 rendendo così necessariauna singola implementazione.Quindi, ove possibile è meglio preferire un Polyfill ad uno Shim. Già, ma come trovarli? Si puòconsultare la lista dei migliori polyfill (https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills) redatta dagli sviluppatori di Modernizr.Un ultimo appunto: se il numero di file javascript dovesse diventare troppo sostanzioso ricordiamociche è sempre possibile ricorrere ad un loader condizionale, come yepnope.js(http://yepnopejs.com/).ConclusioniSiamo alla fine, con queste ultime righe si conclude la guida HTML5 di html.it, in circa 50 lezioniabbiamo sorvolato un pianeta ricco di nuove ed interessanti opportunità, capaci di far evolvere lenostre creazioni web fino a dove pochi anni fa non ritenevamo possibile. In questa lezione abbiamoscoperto come le specifiche si intreccino con il mondo reale e quali sono i potenziali comportamenti difallback da implementare nel caso di assenza di qualche particolare feature. In particolare ci siamoaccorti che per tematiche di basso livello (WebStorage, IndexedDB e Offline Web Application) nonesistono soluzioni alternative, se si esclude Google Gears, che però necessita di una installazionemanuale da parte dellutente finale.Un ultimo punto importante prima di concludere: non tutte le funzionalità proposte dallHTML5 sonoda considerarsi pronte per un uso in fase di produzione, alcune di esse infatti sono ancora in uno
  • 166. stadio di implementazione poco stabile, oppure subiranno a breve importanti cambiamenti nelle loroAPI; per avere un elenco aggiornato di cosa è considerato utilizzabile in produzione e cosa no poteteconsultare la tabella di compatibilità posta in appendice a questa guida.