Adaptive Rendering Css Friendly Adapters Dott. Ing. Giorgetti Alessandro [email protected] www.GruppoSID.com www.dotnetmarche.org Rendering Adattativo Il concetto di rendering adattivo (o più in generale di Adaptive Control Behaviour) nasce originariamente come mezzo per raggiungere una maggiore efficienza e flessibilità nello sviluppo di codice (in applicativi web in generale) quando si tratta di rappresentare il contenuto della stessa pagina su dispositivi differenti. Tipico è il caso di palmari e telefonini in grado di accedere ad internet, essi non sono in grado di renderizzare un pagina web in HTML standard, ma necessitano di un proprio dialetto. Due sono le strade da seguire in questo caso: 1- Riscrivere completamente l’interfaccia utente e realizzarne una versione per ogni dispositivo (utilizzando versioni dedicate dei controlli). 2- Adattare l’interfaccia al device lasciando ai singoli controlli l’incombenza di variare la visualizzazione in base al device stesso. Generalizzazione Se poi si considerano come device distinti, oltre alla moltitudine di sistemi operativi, anche i diversi browser che esistono sul mercato per una stessa piattaforma (ognuno con le proprie peculiarità), si comprende come la tecnologia del rendering adattativo possa di fatto aiutare moltissimo. Il browser può infatti essere correttamente identificato mediante lo UserAgent della richiesta ed il controllo può variare la propria rappresentazione di conseguenza. Adaptive Control Behaviour Il concetto di adattatore (adapter) può esser ulteriormente generalizzato, in .NET si parla di Adaptive Control Behaviour: molti dei punti critici nel ciclo di vita di una entità (sia esso un controllo o l’intera pagina) possono essere intercettati e sostituiti dai corrispondenti metodi di un adapter. E’ possibile infatti intercettare ed adattare altri comportamenti standard dei controlli come ad esempio: il caching, la gestione del view-state o la processazione dei dati di post-back. La Necessità Gli attuali requisiti di design per un sito web impongono un maggiore rispetto della sintassi, delle regole e degli schemi associati ai linguaggi HTML e XHTML. Il buon senso inoltre dovrebbe spingere a non utilizzare in modo scorretto i differenti tag del linguaggio (il tag <table> deve essere usato per rappresentare dati tabulati, non impostare un layout). Inoltre le normative impongono ulteriori limiti: la legge Stanca (in Italia) ed altre normative europee e mondiali definiscono le caratteristiche tecniche (e non solo) minime che un sito deve avere per rispettare degli standard di accessibilità ed essere quindi fruibile da tutti in modo consono. Quando il Framework ‘rema contro’ Tra i principali problemi/difficoltà da affrontare nella costruzione di un sito che rispetti i nuovi standard: 1- Layout e formattazione css-based (evitando gli stili inline il più possibile, idealmente non ce ne dovrebbero essere). 2- Abuso dei tag (ex: <table> nella definizione del layout di una pagina). 3- Utilizzo di attributi e tag considerati obsoleti. I controlli standard di ASP.NET 1.x e 2.0 commettono entrambi questi errori. Come risolvo il problema? .NET 1.x Non si ha molta scelta: per variare il rendering standard del controllo si deve ereditare la classe base del controllo e riscrivere le funzioni di rendering. Ci si scontra in questo caso con la scarsità di documentazione fornita sull’implementazione interna dei controlli. Supporto limitato per Adaptive Rendering .NET 2.0 Adaptive Rendering, supporto esteso. Control Adapter Un Adapter è una classe/oggetto a cui vengono delegate determinate funzioni esposte da un controllo base (siano esse relative alla fase di rendering, gestione del viewstate, ecc…). Control Adapter E’ possibile cambiare completamente il comportamento di un controllo, con un risultato simile a quello che si otterrebbe creando una classe che eredita dal controllo stesso, il vantaggio è che quest’ultima può essere variata in funzione del device ed attivabile inserendo un file di definizione. Esistono diversi tipi di ContolAdapters a seconda del tipo di controllo che si vuole ridefinire: •ControlAdapter - adatto per qualsiasi tipo di controllo. •WebControlAdapter - da usare per tutti quei controlli che ereditano da WebControl. •DataBoundControlAdapter - da usare per ridefinire i controlli che supportano il databound come la GridView. •HierarchicalDataBoundControlAdapter - adatto per i controlli che supportano il caricamento di informazioni gerarchiche come il TreeView o il Menu. Ciclo di vita di una pagina Il Modello di Rendering Durante il ciclo di vita di una pagina, a seguito delle inizializzazioni e dell’handling degli eventi si rende necessario renderizzare il controllo (ovvero produrre codice HTML). L’oggetto Page durante questa fase richiama ricorsivamente la funzione RenderControl() di ogni oggetto control. Al metodo viene passata una istanza della classe HtmlTextWriter (responsabile del rendering dei tag e degli attributi) sotto forma di una delle sue specializzazioni: Html32TextWriter – emette HTML 3.2. XhtmlTextWriter – emette html conforme allo standard xhtml. ChtmlTextWriter – emette compact html per sistemi palmari. Per identificare quale tipo di HtmlTextWriter utlizzare viene analizzata la stringa UserAgent presente in ogni richiesta Web. Questa stringa viene comparata con una lista ben definita di browser ognuno dotato delle proprie caratteristiche e tecnologie supportate. La lista viene definita attraverso una serie di files (.browser files) aderenti ad uno specifico schema. Tra le proprietà supportate vi è proprio la spacifica della classe HtmlTextWriter da utilizzare (tagwriter). Adaptive Rendring di “primo livello” Adattatore (Adapter) Un Adapter deve ereditare dalla classe base System.Web.UI.Adapters.ControlAdapter : una classe astratta che espone i metodi Init(), Load(), Unload(), PreRender() e Render(), ecc… che verranno richiamati in sostituzione di quelli standard dei controlli. Poiché gli adapter nascono per fornire comportamenti alternativi a seconda dei differenti device le informazioni sui mapping vanno specificate nei “.browser files”. Adaptive Rendring di “secondo livello” Adaptive Rendering - Architettura Control (internal rendering functions) No Control.Render() Adapter present? Adapter Mappings Yes Adapter.Render() Mappings e Riconoscimento dei Browser In ASP.NET 1.x il riconoscimento dei browser veniva effettuato mediante le sezione <browserCaps> nel web.config (o nel machine.config). In ASP.NET 2.0 tale metodo viene mantenuto ma si consiglia l’utilizzo dei .browser files: file XML che consentono di specificare le caratteristiche dei differenti browser. Possono risiedere sia nella directory ‘App_Browsers’ all’interno del sito, sia globalmente al persorso ‘%SYSTEM%\Microsoft.NET\Framework\v2.0.5072 7\Config\Browsers’. .browser file - identificazione Utilizzati per popolare la classe HttpBrowserCapabilities che istruisce ASP.NET sulle funzionalità esposte dal browser e su come renderizzare la pagina. Specifica: <browser parentID=“…”> - elemento che definisce un set di capability da assegnare ad uno o più browsers, l’attributo parentID viene utilizzato per identificare una categoria/insieme di browsers all’interno di una ben definita gerarchia. <identification> - subelement contenente le regole di identificazione, espresse come regular expression che devono effettuare matching sulla stringa UserAgent della richiesta. <useragent match=“” /> - subelement che speficica il match di inclusione. <useragent nonMatch=“” /> - subelement che specifica i match di esclusione. Gerarchia dei Browsers .browser file Esempio di definizione delle caratteristiche del browser Internet Explorer <browsers> <browser id="IE" parentID="Mozilla"> <identification> <userAgent match="^Mozilla[^(]*\([C|c]ompatible;\s*MSIE (?’version’(?’major’\d+)(?’minor’\.\d+)(?’letters’\w*)) (?’extra’[^)]*)" /> <userAgent nonMatch="Opera|Go\.Web|Windows CE|EudoraWeb" /> </identification> <capabilities> <capability name="browser" value="IE" /> <capability name="extra" value="${extra}" /> <capability name="isColor" value="true" /> … .browser file – mapping degli adapter Il tipo System.Web.UI.Control dispone di una proprietà Adapter che restituisce l'oggetto incaricato di operare le normali operazioni di un controllo per uno specifico device. Per creare l’oggetto il metodo ResolveAdapter() identifica il dispositivo in base alle definizioni dei browser: Viene analizzata la sezione controlAdapters del tag browser. controlAdapters è costituito da una lista di tag adapter indicanti la coppia controlType/adapterType. .browser file - CssAdapterControls <browsers> <browser refID="Default"> <controlAdapters> <adapter controlType="System.Web.UI.WebControls.Menu" adapterType="CSSFriendly.MenuAdapter" /> <adapter controlType="System.Web.UI.WebControls.TreeView" adapterType="CSSFriendly.TreeViewAdapter" /> <adapter controlType="System.Web.UI.WebControls.DetailsView" adapterType="CSSFriendly.DetailsViewAdapter" /> … </controlAdapters> </browser> <browser id="W3C_Validator" parentID="default"> <identification> <userAgent match="^W3C_Validator" /> </identification> <capabilities> <capability name="browser" value="W3C Validator" /> <capability name="ecmaScriptVersion" value="1.2" /> … <capability name="tagWriter" value="System.Web.UI.HtmlTextWriter" /> <capability name="w3cdomversion" value="1.0" /> </capabilities> </browser> </browsers> CSS Friendly Adapters Si tratta di una serie di Adapters appositamente creati per far fronte alla duplice necessità da parte degli web-designer di avere controlli che renderizzino un layout corretto e poter specificare tutti gli attributi di stile per i controlli utilizzando i fogli di stile invece che ricorrere ad attributi server-side. Tutti gli attributi di stile vengono incapsulati in una stessa classe CSS, in questo modo è possibile creare stili diversi associati a classi diverse. E’ possibile specificare il set di stili associato ad un particolare controllo ricorrendo all’attributo CssSelectorClass. Per garantire il corretto wiring degli eventi (generati dai controlli adattati) le funzioni di gestione devono essere specificare ricorrendo ad attributi che inizino con il prefisso OnAdapted (ex per una treeview: OnSelectedNodeChanged="SelectedNodeChanged“ OnAdaptedSelectedNodeChanged="SelectedNodeChanged“). Alcuni eventi tipici di determinati controlli potrebbero non essere più supportati a causa dell’override delle funzioni di generazione degli eventi di postback (ex: gli eventi expand e collapse della treeview). CSS Friendly Adapters - Utilizzo • Istallare lo Starter Kit (http://www.asp.net/cssadapters/). • Creare un nuovo sito web mediante i template messi a disposizione dallo Starter Kit. • Copiare il file CssFriendlyAdapters.browser nella directory App_Browsers del sito di destinazione. • Copiare il contenuto della directory Adapters situata in App_Code nella corrispondnete posizione nel sito di destinazione. • Copiare la directory CSS situata nella root del sito nella corrispondente posizione del sito di destinazione. • Copiare la directory Javascript situata nella root del sito nella corrispondente posizione del sito di destinazione. • Inserire in ogni pagina che deve utlizzare gli adapters (meglio se nelle master page) i link ai file css comuni utilizzando le direttive: <link runat="server" rel="stylesheet" href="~/CSS/Import.css" type="text/css" id="AdaptersInvariantImportCSS" /> <!--[if lt IE 7]> <link runat="server" rel="stylesheet" href="~/CSS/BrowserSpecific/IEMenu6.css" type="text/css" id="IEMenu6CSS" /> <![endif]--> • Creare gli opportuni fogli di stile nella cartella App_Themes. • Settare nel web.config l’elemento xhtmConformance a strict (<xhtmlConformance mode="Strict"/>) in modo da indicare all’engine Asp.NET di renderizzare gli elemnti in conformità allo standard xhtml. CSS Friendly Adapters Esempio HTML <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Untitled Page</title> <link runat="server" rel="stylesheet" href="~/CSS/Import.css" type="text/css" id="AdaptersInvariantImportCSS" /> <!--[if lt IE 7]> <link runat="server" rel="stylesheet" href="~/CSS/BrowserSpecific/IEMenu6.css" type="text/css" id="IEMenu6CSS" /> <![endif]--> </head> <body> <form id="form1" runat="server"> <div id="layout"> … <asp:Menu CssSelectorClass="MyMenu" ID="mnuHorizontal" runat="server" DataSourceID="xmlHorizontal" Orientation="Horizontal"> <DataBindings> <asp:MenuItemBinding DataMember="siteMapNode" TextField="title" NavigateUrlField="url" /> </DataBindings> </asp:Menu> CSS Friendly Adapters Esempio CSS .MyMenu { background-color: #B9C7E4; width: 100%; } .MyMenu ul.AspNet-Menu /* Tier 1 */ { left: 160px; } .MyMenu ul.AspNet-Menu ul /* Tier 2 */ { width: 10em; top: 100%; left: 0; border: 1px solid #003398; } .MyMenu ul.AspNet-Menu ul ul /* Tier 3+ */ { top: 0em; left: 10em; border: 1px solid #003398; } .MyMenu li /* all list items */ { width: 10em; background-color: #B9C7E4; color: #003398; } .MyMenu li:hover, /* list items being hovered over */ .MyMenu li.AspNet-Menu-Hover { background: Black; } .MyMenu a, /* all anchors and spans (nodes with no link) */ .MyMenu span { color: #003398; padding: 4px 2px 4px 8px; } DEMO Mammuth s.r.l. DEMO DEMO DEMO DEMO Limiti degli Adapter Controls Molti degli attributi di stile e formattazione impostabili nel designer vengono completamente ignorati, tutta la formattazione viene fatta mediante classi css. Non tutti gli eventi standard di un controllo vengono gestiti (gli eventi collapse ed expand di una treeview ad esempio). Necessitano ancora di alcune piccole correzioni per generare codice completamente ‘accessibile’ soprattutto in caso di rendering di liste di elementi prive di contenuto. DOMANDE ? (Spero di no)