This book was produced in EPUB format by the Internet Archive.

The book pages were scanned and converted to EPUB format automatically. This process relies on optical character recognition, and is somewhat susceptible to errors. The book may not offer the correct reading sequence, and there may be weird characters, non-words, and incorrect guesses at structure. Some page numbers and headers or footers may remain from the scanned page. The process which identifies images might have found stray marks on the page which are not actually images from the book. The hidden page numbering which may be available to your ereader corresponds to the numbered pages in the print edition, but is not an exact match; page numbers will increment at the same rate as the corresponding print edition, but we may have started numbering before the print book's visible page numbers. The Internet Archive is working to improve the scanning process and resulting books, but in the meantime, we hope that this book will be useful to you.

The Internet Archive was founded in 1996 to build an Internet library and to promote universal access to all knowledge. The Archive's purposes include offering permanent access for researchers, historians, scholars, people with disabilities, and the general public to historical collections that exist in digital format. The Internet Archive includes texts, audio, moving images, and software as well as archived web pages, and provides specialized services for information access for the blind and other persons with disabilities.

Created with hocr-to-epub (v.0.0.1)

ARKAITZ GARRO CAPÍTULO 1 ¿QUE ES HTML5? 1.1 Especificación oficial 1.2 5 Tips CAPÍTULO 2 SEMANTI CA 2.1 Cabecera del documento 2.2 Nuevas etiquetas semánticas 2.3 Estructura de un documento HTML5 2.4 Uso de las nuevas etiquetas semánticas 2.5 Atributos globales CAPÍTULO 3 ELEMENTOS DE FORMULARIO 3.1 Nuevos tipos de input 3.2 Nuevos atributos 3.3 Nuevos elementos CAPÍTULO 4 QUE ES MODERNIZR 4.1 Añadir Modernizr a una página 4.2 Objeto Modernizr 4.3 Clases CSS en Modernizr 4.4 El método 1loaa() CAPÍTULO 5 DATASET 5.1 Utilización de los data attributes 5.2 data attributes y JavaScript CAPÍTULO 6 MULTI MEDIA 6.1 Vídeo 6.2 Codecs, la nueva guerra 6.3 API multimedia 6.4 Fullscreen video 6.5 Audio CAPÍTULO 7 CANVAS CAPÍTULO 10 DRAG AND DROP 10.1 Detección de la funcionalidad 10.2 Creación de contenido arrastrable 10.3 Eventos de arrastre 10.4 Arrastre de archivos CAPÍTULO 11 GEOLOCALI ZACI ON 11.1 Métodos del API CAPÍTULO 12 WEB WORKERS 12.1 Transferencia de mensajes 12.2 Utilización de Web Workers 12.3 Subworkers 12.4 Gestionar errores 12.5 Seguridad CAPÍTULO 13 WEBSOCKETS 13.1 Introducción 13.2 Crear un WebSocket 13.3 Comunicación con el servidor 13.4 WebSocket en el servidor CAPÍTULO 14 EVENTSOURCE 14.1 EventSource en el servidor CAPÍTULO 15 FILE 15.1 Detección de la funcionalidad 15.2 Acceso a través del formulario 15.3 Cómo leer archivos 15.4 Fragmentación de archivos CAPÍTULO 16 HISTORY 16.1 API CAPÍTULO 17 XMLHTTPREQUEST2

7.1 Elementos básicos 7.2 Dibujar formas 7.3 Rutas 7.4 Colores 7.5 Degradados y patrones 7.6 Transparencias 7.7 Transformaciones 17.1 Recuperación de archivos 17.2 Especificación de un formato de respuesta 17.3 Envío de datos 17.4 Subida de archivos o Blob 17.5 Subida de un fragmento de bytes 17.6 Ejemplos prácticos ¡ ¡ CAPÍTULO 18 7.8 Animaciones í EJERCICIOS CAPITULO 8 ALMACENAMIENTO LOCAL 18.1 Capítulo 2 8.1 Web Storage ne pa 8.2 Web SQL ad Pa se 8.3 IndexedDB .4 Capítulo 5 ; 18.5 Capítulo 6 CAPITULO 9 18.6 Capítulo 7 18.7 Capítulo 8 18.8 Capítulo 9 18.9 Capítulo 10 18.10 Capítulo 11 18.11 Capítulo 12 18.12 Capítulo 13 SIN CONEXIÓN 9.1 El archivo de manifiesto de caché 9.2 Cómo servir el manifiesto 9.3 Proceso de cacheado 9.4 Actualización de la memoria caché 9.5 Eventos online/offline SOBRE ESTA EDICIÓN HTML5 Publication date: 28/01/2014 This book was published with easybook v5.0-DEV, a free and open-source book publishing application developed by Javier Eguiluz using several Symfony components. LICENCIA Esta obra se publica bajo la licencia Creative Commons Reconocimiento - No Comercial - Compartir Igual 3.0, cuyos detalles puedes consultar en http: //creativecommons.org/licenses/by-nc-sa/3.0/es/. Puedes copiar, distribuir y comunicar públicamente la obra, incluso transformándola, siempre que cumplas todas las condiciones siguientes: Reconocimiento: debes reconocer siempre la autoría de la obra original, indicando tanto el nombre del autor (Arkaitz Garro) como el nombre del sitio donde se publicó originalmente www.arkaitzgarro.com. Este reconocimiento no debe hacerse de una manera que sugiera que el autor o el sitio apoyan el uso que haces de su obra. No comercial: no puedes utilizar esta obra con fines comerciales de ningún tipo. Entre otros, no puedes vender esta obra bajo ningún concepto y tampoco puedes publicar estos contenidos en sitios web que incluyan publicidad de cualquier tipo.

Compartir igual: si alteras o transformas esta obra o si realizas una obra derivada, debes compartir tu trabajo obligatoriamente bajo esta misma licencia.

— Anterior Siguiente => CAPÍTULO 1 ¿QUÉ ES HTML5? HTML5 (HyperText Markup Language, versión 5) es la quinta revisión del lenguaje HTML. Esta nueva versión (aún en desarrollo), y en conjunto con CSS3, define los nuevos estándares de desarrollo web, rediseñando el código para resolver problemas y actualizándolo así a nuevas necesidades. No se limita solo a crear nuevas etiquetas o atributos, sino que incorpora muchas características nuevas y proporciona una plataforma de desarrollo de complejas aplicaciones web (mediante los APIs). HTML5 está destinado a sustituir no sólo HTML 4, sino también XHTML 1 y DOM Nivel 2. Esta versión nos permite una mayor interacción entre nuestras páginas web y el contenido media (video, audio, entre otros) así como una mayor facilidad a la hora de codificar nuestro diseño básico. Algunas de las nuevas características de HTML5 serían: e Nuevas etiquetas semánticas para estructurar los documentos HTML, destinadas a remplazar la necesidad de tener una etiqueta

que identifique cada bloque de la página. Los nuevos elementos multimedia como y . La integración de gráficos vectoriales escalables (SVG) en sustitución de los genéricos , y un nuevo elemento que nos permite dibujar en él. El cambio, redefinición o estandarización de algunos elementos, como , O

. e MathML para fórmulas matemáticas. Almacenamiento local en el lado del cliente. Y otros muchos nuevos APIs que veremos a lo largo de los siguientes capítulos. 1.1 ESPECIFICACIÓN OFICIAL El organismo W3C elabora las normas a seguir para la creación de las páginas HTML5. Sin embargo, no es necesario conocer todas estas especificaciones, escritas es un lenguaje bastante formal, para diseñar páginas con este lenguaje. Las normas oficiales están escritas en inglés y se pueden consultar de forma gratuita en las siguientes direcciones: e Especificación recomendada como candidata para HTML5 e Borrador para la especificación oficial de HTML 5.1

1,23. WMPS 1.2.1 HTML5 ES API Se puede pensar en HTML sólo como nuevas etiquetas y geolocalización. Pero esta no es más que una pequeña parte del estándar que define HTML5. La especificación de HTML5 define también cómo esas etiquetas interactúan con JavaScript, a través del Modelo de Objetos de Documento (DOM). HTML5 no es únicamente definir una etiqueta como , también existe su correspondiente API para objetos de vídeo en el DOM. Se puede utilizar esta API para detectar el soporte para diferentes formatos de vídeo, reproducir el vídeo, hacer una pausa, silenciar el audio, realizar un seguimiento de la cantidad de vídeo que se ha descargado, y todo lo que necesita para crear una completa experiencia de usuario alrededor de la etiqueta en sí. 1.2.2 NO HAY QUE TIRAR NADA A LA BASURA Se puede amar, o se puede odiar, pero no se puede negar que HTML 4 es el formato de marcado más exitoso de la historia. HTML5 se basa en ese éxito. No es necesario volver a aprender cosas que ya se conocen. Si la aplicación web que funcionaba ayer en HTML 4, hoy funcionará en HTML5. Ahora, si lo que se desea es mejorar las aplicaciones web, este es el lugar correcto. He aquí un ejemplo concreto: HTML5 soporta todos los controles de formulario de HTML 4, pero también incluye nuevos controles de entrada. Algunos de estos son funcionalidades esperadas durante mucho tiempo, como reguladores y selectores de fecha, mientras que otros son más sutiles. Por ejemplo, el tipo de entrada de correo electrónico se parece a un cuadro de texto, pero los navegadores móviles personalizar su teclado en pantalla para que sea más fácil de escribir direcciones de correo electrónico. Los navegadores más antiguos que no son compatibles con el tipo de entrada de correo electrónico será tratado como un campo de texto normal, y el formulario sigue funcionando sin ningún cambio en las etiquetas o hacks de JavaScript. 1.2.3 FÁCIL DE COMENZAR "Actualizar" a HTML5 puede ser tan simple como cambiar su tipo de documento. El tipo de documento debe estar en la primera línea de cada página HTML. Las versiones anteriores de HTML definen un montón de doctypes, y elegir el más adecuado puede ser difícil. En HTML5, sólo hay un tipo de documento: <1DOCIAAS Imeámul> La actualización al doctype HTML5 no rompe el marcado existente, ya que los elementos obsoletos previamente definidas en HTML 4 todavía se representará en HTML5. Pero le permitirá usar (y validar) nuevos elementos semánticos como

,

,

Y

.

1.2.4 ¡YA FUNCIONA! Si se quiere dibujar en un lienzo, reproducir vídeo, diseñar mejores formas, o construir aplicaciones web que funcionan offline, nos encontramos con que HTML5 ya está bien soportado. Firefox, Safari, Chrome, Opera y los navegadores móviles ya son compatibles con canvas, video, la geolocalización, el almacenamiento local, y más funcionalidades. Incluso Microsoft (raramente conocido por el soporte de estándares) soporta la mayoría de las características de HTML5 en Internet Explorer 9. 1.2.5 HA VENIDO PARA QUEDARSE Tim Berners-Lee inventó la World Wide Web a principios de 1990. Más tarde fundó el W3C para que actuase como administrador único de los estándares web, lo que venido haciendo durante más de 15 años. Esto es lo que el W3C tenía que decir sobre el futuro de los estándares web, en julio de 2009: Hoy, el director anuncia que cuando el XHTML 2 expire en la fecha prevista a finales de 2009, no será renovado. De este modo, y mediante el aumento de los recursos en el Grupo de Trabajo de HTML, el W3C espera acelerar el progreso de HTML5 y aclarar la posición del W3C sobre el futuro de HTML. En septiembre de 2012, el W3C propuso un plan para crear una primera especificación de HTML5 a finales de 2014, y una nueva especificación final de HTML 5.1 a finales 2016. Al igual que ocurre en la especificación de CSS3, en HTML5 se ha optado por modularizar la especificación, creando grupos de trabajo que trabajan de forma separada en diferentes aspectos del estándar. Algunas de las especificaciones sobre las que se está trabajando: e HTML Microdata - HTML WG e HTML Canvas 2D Context - HTML WG e HTML5 Web Messaging - Web Apps WG e Web Workers - Web Apps WG e Web Storage - Web Apps WG e The WebSocket API - Web Apps WG e The WebSocket Protocol - I|ETF HyBi WG e Server-Sent Events - Web Apps WG e WebRTC - WebRTC WG e WebVTT - W3C Web Media Text Tracks CG ÍNDICE DE CONTENIDOS ¿Qué es HTML5? 1.1 Especificación oficial 1.2 5 Tips

— Anterior Siguiente => CAPÍTULO 2 SEMÁNTICA Una de las novedades que hemos mencionado anteriormente son las etiquetas que se han introducido en HTML5. Existen más de 30 nuevas etiquetas semánticas que pueden ser utilizadas en nuestras páginas estáticas. Estas nuevas etiquetas se podrían clasificar en dos grupos: e Etiquetas que extienden a las actuales, como , O , y QUe además añaden nuevas funcionalidades a los documentos HTML, que podemos controlar desde JavaScript y e etiquetas que componen la web semántica, es decir, que no proponen nuevas funcionalidades pero sirven para estructurar sitios web, y añadir un significado concreto, más allá de las etiquetas generales como

. En este capítulo, veremos como transformar nuestra estructura actual de marcado basada en

, a Una estructura que utiliza las nuevas etiquetas estructurales como

,

,

,

, O

. 2.1 CABECERA DEL DOCUMENTO Además de las nuevas etiquetas introducidas por HTML5 (que veremos más adelante), el nuevo estándar propone pequeñas mejoras que podemos aplicar en la definición de nuestros documentos, en concreto en la cabecera de los mismos. 2.1,1 DOCTYPE El estándar XHTML deriva de XML, por lo que comparte con él muchas de sus normas y sintaxis. Uno de los conceptos fundamentales de XML es la utilización del DTD o Document Type Definition ("Definición del Tipo de Documento”). El estándar XHTML define el DTD que deben seguir las páginas y documentos XHTML. En este documento se definen las etiquetas que se pueden utilizar, los atributos de cada etiqueta y el tipo de valores que puede tener cada atributo. TA OE o/o darian stilo tata Ésta es una de las 15 declaraciones posibles declaradas en los estándares HTML4 y XHTML. En HTML5 se reduce la definición del tipo de documento a una única posibilidad, por lo que no tenemos que preocuparnos de elegir el tipo de documento correcto:

< DOSIS 2.1.2 ELEMENTO RAÍZ HTML En todo documento HTML, su elemento raíz o nodo superior siempre es la etiqueta . Hasta ahora, este elemento raíz se definía de la siguiente manera: No hay ningún problema en mantener esta sintaxis. Si se desea, se puede conservar, ya que es válido en HTML5. Sin embargo, algunas de sus partes ya no son necesarias, por lo que podemos eliminarlas. El primer elemento del que podemos prescindir es el atributo xm1ns. Se trata de una herencia de XHTML 1.0, que dice que los elementos de esta página están en el espacio de nombres XHTML, http: //www.w3.org/1999/xhtm1. Sin embargo, los elementos de HTML5 están siempre en este espacio de nombres, por lo que ya no es necesario declararlo explícitamente. Eliminar el atributo xm1ins nos deja con este elemento de la siguiente manera: En este caso ocurre lo mismo con el atributo xml: lang, es una herencia de XHTML que podemos eliminar, quedando finalmente la etiqueta de la siguiente manera: 2.1.3 ELEMENTO HEAD El primer hijo del elemento raíz es generalmente el elemento head. El elemento head contiene los metadatos que aportan información extra sobre la página, como su título, descripción, autor, etc. Además, puede incluir referencias externas a contenidos necesarios para que el documento se muestre y comporte de manera correcta (como hojas de estilos o scripts). Este elemento ha sufrido pequeñas variaciones, pero que debemos tener en cuenta: My Weblog

title="My Weblog search" href="opensearch.xml" /> 2.1.3.1 CODIFICACIÓN DEL CONTENIDO Cuando se piensa en "texto", probablemente nos venga a la cabeza una definición de "caracteres y símbolos que veo en la pantalla de mi ordenador". Pero realmente se tratan de bits y bytes. Cada cadena de caracteres que se muestra en la pantalla, se almacena con una codificación de caracteres en particular. Hay cientos de codificaciones de caracteres diferentes, algunos optimizado para ciertos idiomas como el ruso, el chino o inglés, y otros que se pueden utilizar para múltiples idiomas. En términos generales, la codificación de caracteres proporciona una correspondencia entre lo que se muestra en la pantalla y lo que un equipo realmente almacena en la memoria y en el disco. Se puede pensar en la codificación de caracteres como una especie de clave de descifrado del texto. Cuando accedemos a una secuencia de bytes, y decidimos que es "texto", lo que necesitamos saber es qué codificación de caracteres se utiliza para que pueda decodificar los bytes en caracteres y mostrarlos (o transformarlos) de manera correcta. Lo ideal es establecer esta codificación en el servidor, indicando el tipo en las cabeceras de respuesta: Content-Type: text/html; charset="utf-8" Por desgracia, no siempre podemos tener el control sobre la configuración de un servidor HTTP. Por ejemplo, en la plataforma Blogger, el contenido es proporcionado por personas, pero los servidores son administrados por Google, por lo que estamos supeditados a su configuración. Aún así, HTML 4 proporciona una manera de especificar la codificación de caracteres en el documento HTML: El encabezado HTTP es el método principal, y anula la etiqueta si está presente. Pero no todo el mundo puede establecer encabezados HTTP, por lo que la etiqueta todavía tiene sentido. En el caso de HTML5, es aún más sencillo definir esta etiqueta meta: Debemos acostumbrarnos a especificar la codificación de nuestros documentos, aunque no vayamos a utilizar caracteres especiales o nuestro documentos no se presente en otros idiomas. Si no lo hacemos, podemos exponernos a problemas de seguridad.

2.1.3.2 LINKS Dentro del elemento head, las etiquetas <1ink> son una manera de acceder o declarar contenido externo al documento actual, que puede cumplir distintos objetivos: e Es una hoja de estilo contiene las reglas CSS que su navegador debe aplicar al presente documento. Es un feed que contiene el mismo contenido que esta página, pero en un formato estándar (RSS). Es una traducción de esta página en otro idioma. Es el mismo contenido que esta página, pero en formato PDF. Es el próximo capítulo de un libro en línea de la cual esta página es también una parte. En HTML5, se separan estas relaciones de enlace en dos categorías: e Enlaces a recursos externos que se van a utilizar para mejorar el documento actual, e y enlaces de hipervínculos que son enlaces a otros documentos. El tipo de relación más utilizado (literalmente) es el siguiente: Esta relación es utilizada para indicar el archivo donde se almacenan las reglas CSS que se desean aplicar al documento. Una pequeña optimización que se puede hacer en HTML5 es eliminar el atributo type. Sólo hay un lenguaje de estilo para la web, CSS, así que ese es el valor predeterminado para el atributo type: 2.2 NUEVAS ETIQUETAS SEMÁNTICAS En 2004, lan Hickson, el autor de la especificación de HTML5, analizó 1.000.000.000 de páginas web utilizando el motor de Google, intentando identificar la manera en la que la web real estaba construida. Uno de los resultados de este análisis, fue la publicación de una lista con los nombres de clases más utilizados. Este estudio revela que los desarrolladores utilizan clases o |Ds comunes para estructurar los documentos. Esto llevó a considerar que quizás fuese una buena idea crear etiquetas concretas para reflejar estas estructuras. Este tipo de etiquetas que componen la web semántica nos sirven para que cualquier mecanismo automático (un navegador, un motor de búsqueda, un lector de feeds...) que lea un sitio web sepa con exactitud qué partes de su contenido corresponden a cada una de las partes típicas de un sitio. Observando esas etiquetas semánticas estructurales,

cualquier sistema podrá procesar la página y saber cómo está estructurada. Veamos algunas de estas etiquetas que introduce HTML5 en este sentido. e

: se utiliza para representar una sección "general" dentro de un documento o aplicación, como un capítulo de un libro. Puede contener subsecciones y si lo acompañamos de hi-h6 podemos estructurar mejor toda la página creando jerarquías del contenido, algo muy favorable para el buen posicionamiento web. e

: representa un componente de una página que consiste en una composición autónoma en un documento, página, aplicación, o sitio web con la intención de que pueda ser reutilizado y repetido. Podría utilizarse en los artículos de los foros, una revista o el artículo de periódico, una entrada de un blog, un comentario escrito por un usuario, un widget interactivo o cualquier otro artículo independiente de contenido. Cuando los elementos de

son anidados, los elementos interiores representan los artículos que en principio son relacionados con el contenido del artículo externo. Por ejemplo, un artículo de un blog que permite comentarios de usuario, dichos comentarios se podrían representar con

. e

: representa una sección de la página que abarca un contenido relacionado con el contenido que lo rodea, por lo que se le puede considerar un contenido independiente. Este elemento puede utilizarse para efectos tipográficos, barras laterales, elementos publicitarios, para grupos de elementos de la navegación, u otro contenido que se considere separado del contenido principal de la página. e

: representa un grupo de artículos introductorios o de navegación. Está destinado a contener por lo general la cabecera de la sección (un elemento h1-n6 o un elemento hgroup), pero no es necesario. e

: representa una sección de una página que enlaza a otras páginas o a otras partes dentro de la página. No todos los grupos de enlaces en una página necesita estar en un elemento nav, sólo las secciones que constan de bloques de navegación principales son apropiados para el elemento de navegación. e

: representa el pie de una sección, con información acerca de la página/sección que poco tiene que ver con el contenido de la página, como el autor, el copyright o el año. e

: representa el encabezado de una sección. El elemento se utiliza para agrupar un conjunto de elementos h1-h6 cuando el título tiene varios niveles, tales como subtítulos o títulos alternativos. e : representa o bien una hora (en formato de 24 horas), o una fecha precisa en el calendario gregoriano (en formato 1|SO), opcionalmente con un tiempo y un desplazamiento de zona horaria.

2.3 ESTRUCTURA DE UN DOCUMENTO HTML5 Como hemos visto con las nuevas etiquetas semánticas introducidas en HTML5, éstas aportan un significado concreto al documento que estamos definiendo, y por lo tanto, afectan de manera directa a la forma en la estructuramos el contenido. Vamos a ver como podemos convertir nuestra actual página con las nuevas etiquetas introducidas en HTML5. 2.3.1 ESTRUCTURA TRADICIONAL DE UN DOCUMENTO EN HTML 4 El siguiente código muestra una estructura "clásica" de documento HTML, donde los diferentes contenidos de la web se encuentran agrupados por etiquetas

. Por sí mismas, estas etiquetas no aportan ningún tipo de significado, y el atributo ia tampoco se lo proporciona. Si cambiamos

por

, el significado sigue siendo el mismo, ninguno.

e k

My Weblog

A lot of effort went into making this effortless.

home1i>

blog1i>

gallery1i>

about1i>

<>

October 22, 2009

Travel day Content goes here... AQ

3 comments

ETS

<>

6+167;

6+169; 2013£t8211;9 Arkaitz Garro

A lot of effort went into making this effortless. ZO

home1i> AS Alo

gallery1i>

about1i>

October 22, 2009

Travel day

Content goes here...

3 comments

diiy>

8+t167;

8e++169; 2013£$8211;9 Arkailtz Garro

males Partiendo de la anterior estructura, parece evidente las nuevas etiquetas que debemos utilizar. Esto no siempre es así, y cuando estructuramos contenidos de mucho mayor alcance, lo normal es que nos surjan dudas. Un sencillo algoritmo que nos puede ayudar

en la correcta selección de etiquetas, es el que proponen en HTML5 Doctor. Doctor HIML5 Element Flowchart Sectioning content elements and friends By Oriddle € boblet www.htmiSdoctor.com A block of flow content (not inline phrasing content) Sidebar, comments section, pullquote, glossary, advertising, footnote etc that's tangentially related to the page or content... => htmi5doctor.com/aside Isit ired to vederslcnd the Isit a major block? current content? navigation Could you move Is it logical itto an appendix?, to add a heading Doesit have any semantics? 2

Flow content with no additional semantics, Site or in-page News article, weblog or e.g. for CSS hooks... navigation (anything forum post, comment E ; you'd use a “skip to on an article, sidebar lid nav” link for) widget etc, with a heading... = htmi5doctor.com/article > htmi5doctor.com/nav A

One or more images, A section of the page, Probably

, but graphics, code samples or chapter of an possibly

, etc, plus optional

, with a

,

...

... heading... = htmi5doctor.com/semantics = htmi5doctor.com/figure = htmi5doctor.com/section *Sectioning content element These four elements (and their headings) are used by 2011-07-22 v1.5 HTMLS's outlining algorithm to make the document's outline For more information: => htmi5doctor.com/outline www.hitmiSdoctor.com/semantics 2.4 USO DE LAS NUEVAS ETIQUETAS SEMÁNTICAS 2.4.1

 Según la especificación, un elemento

 representa lo siguiente: Un grupo de navegación o contenido introductorio. Un elemento header normalmente contiene una sección de encabezado (un elemento h1-h6 o un elemento hgroup), pero puede contener otro tipo de elementos, como una tabla de contenidos, un formulario de búsqueda o cualquier logo importante. En nuestro ejemplo, y en la mayoría de los sitios web, la cabecera contiene los primeros elementos de la página. Tradicionalmente el título de la web, su logo, enlaces para volver al inicio... De la manera más simple, nuestra cabecera quedaría de esta forma:  home

 Tic LS ms

  También es muy común que los sitios web muestren un lema o subtítulo bajo el título

principal. Para dar mayor importancia a este subtítulo, y relacionarlo de alguna manera con el título principal de la web, es posible agrupar los dos titulares bajo un elemento

. home

A lot of effort went into making this effortless.

2.4.2 ENAV> Según la especificación, un elemento

representa lo siguiente: El elemento

representa una sección de una página que enlaza con otras páginas o partes de la misma página: una sección con enlaces de navegación. El elemento

ha sido diseñado para identificar la navegación de un sitio web. La navegación se define como un conjunto de enlaces que hacen referencia a las secciones de una página o un sitio, pero no todos los enlaces son candidatos de pertenecer a un elemento

: una lista de enlaces a patrocinadores o los resultados de una búsqueda, no forman parte de la navegación principal, sino que corresponden con el contenido de la página. Como ocurre con los elementos

,

y el resto de nuevas etiquetas, no estamos obligados a utilizar un único elemento

en toda la página. Es posible que tengamos una navegación principal en la cabecera de la página, una tabla de contenidos o enlaces en el pie de la página, que apuntan a contenidos secundarios. Todos ellos son candidatos a pertenecer a un elemento

.

Giles

home1:1> ao

gallery1li>

about1i>

2.4.3

Según la especificación, un elemento

representa lo siguiente:

Representa el pie de una sección. Un pie tradicionalmente contiene información acerca de su sección, como quién escribió el contenido, enlaces relacionados, copyright y similares. Al igual que ocurre con el elemento

, podemos tener tantos elementos

como sea necesario. Lo normal es que nuestro sitio web disponga de al menos un pie principal, que contiene los avisos legales (privacidad, condiciones del servicio, copyright...), mapa del sitio web, accesibilidad, contacto y otros muchos enlaces que pueden ir incluidos en un elemento

. 2.4,4 REO Según la especificación, un elemento

representa lo siguiente: Este elemento representa un contenido completo, auto-contenido en un documento, página, aplicación o sitio web, que es, en principio, independiente de ser distribuido y reutilizado, por ejemplo en un RSS. Puede ser un post de un foro, un artículo de un periódico o revista, una entrada de un blog, un comentario de un usuario, un widget o cualquier otro elemento independiente. Cuando los artículos están anidados, los artículos interiores representan contenido que en principio está relacionado con el artículo que los contiene. Por ejemplo, una entrada de un blog puede aceptar comentarios de usuarios, que están incluidos dentro del contenido principal y relacionados con el mismo. Por lo tanto, la etiqueta

se utiliza para encapsular contenido, que tiene significado en sí mismo, y que puede ser distribuido y reutilizado en otros formatos de datos. No nos referimos únicamente a contenidos clásicos de texto, sino que incluso un contenido multimedia con su transcripción, un mapa o email pueden ser totalmente válidos para ser incluidos en una etiqueta

.

Comments

Posted by: George Washington

15 minutes ago

Yeah! Especially when talking about your lobbyist friends!

Posted by: George Hammond

5 minutes ago

Hey, you have the same first name as me.

2.4.5 ESECIUTÓON> A diferencia del elemento

, este elemento es utilizado para dividir el documento (o artículos) en diferentes áreas, o como su propio nombre indica, en secciones. Según la especificación, un elemento

representa lo siguiente: Representa una sección genérica de un documento o aplicación. Una sección, en este contexto, es un grupo temático de contenido, que generalmente incluye una | Cabecera. Consideremos el siguiente marcado válido en HTML 4: Rules for Munchkins

Yellow Brick Road

It is vital that Dorothy follows it-so no selling bricks as "souvenirs"

Btan Club úntrorms

A11 Munchkins are obliged to wear their "I'm a friend F of Dorothy!" t-shirt when representing the club

Vital caveat about the information above: does not apply on the first Thursday of the month.

En este caso, y desde un punto de vista semántico, es complicado deducir si el texto Vital caveat about the information above: does not apply on the first Thursday of the month. pertenece al contenido completo o está relacionado con la sección Fan Club uniforms. Gracias a la etiqueta

, es muy sencillo separar e identificar a qué sección pertenece cada contenido:

Rules for Munchkins

Yellow Brick Road

e viral ase Dorocay rollos 130 me sel iliime; bricks as "souvenirs"

Fan Club uniforms

A11 Munchkins are obliged to wear their " I'm a friend of Dorothy!" t-shirt when representing the club

Vital caveat about the information above: does not apply on the first Thursday of the month.

Rules for Munchkins

Yellow Brick Road

le e válieel aer Dorawciay col lows 1-30 me sel lime; bricks as "souvenirs"

Fan Club uniforms

A11 Munchkins are obliged to wear their " I'm a friend of Dorothy!" t-shirt when representing the club

Vital caveat about the information above: does not apply on the first Thursday of the month.

Como podemos observar en los dos ejemplos anteriores, es muy sencillo agrupar contenido que pertenece a una misma sección, permitiendo incluirlo dentro de un contexto semántico. Otra de las posibilidades que nos ofrece esta etiqueta, es la de dividir nuestro documento en secciones, que incluyen contenido de temáticas diferentes entre sí. Si además queremos separar estos contenidos visualmente en dos columnas, lo lógico sería utilizar las tradicionales etiquetas

para agrupar los artículos según su temática, y posteriormente aplicar estilos CSS o JavaScript para presentarlos en forma de pestañas. En este caso, la etiqueta

no nos aporta ningún significado semántico, tan sólo estructural. La etiqueta

es la encargada de añadir semántica en estos casos:

Articles about l1lamas

The daily llama:

blah blah

Buddhism and South American camelids

Sshh! Do not alarm a llama

blah blah

Articles about root vegetables

Carrots: the orange miracle

blah blah

Eat more Swedes (the vegetables, not the people)

blah blah

2.4.6 KASIDE> Según la especificación, un elemento

representa lo siguiente: Una sección de una página que consiste en contenido tangencialmente relacionado con el contenido alrededor del elemento, y puede considerarse separado de este contenido. Estas secciones son normalmente representadas como elementos laterales en medios impresos. Este elemento puede utilizarse contener citas, anuncios, grupos de elementos de navegación y cualquier otro contenido separado del contenido principal de la pagina. Dentro de un artículo, por ejemplo, puede ser utilizado para mostrar contenido relacionado como citas u otros artículos relacionados. 2.4.7

Según la especificación, un elemento

representa lo siguiente: The figure element represents some flow content, optionally with a caption, that is self- contained and is typically referenced as a single unit from the main flow of the document. The element can be used to annotate illustrations, diagrams, photos, code listings, etc. This includes, but is not restricted to, content referred to from the main part of the document, but that could, without affecting the flow of the document, be moved away from that primary content, e.g. to the side of the page, to dedicated pages, or to an appendix. Hasta ahora, no había una manera correcta de poder añadir un subtítulo o una leyenda a un contenido concreto, como explicar una figura o atribuir una imagen a un fotógrafo. Gracias a la etiqueta

podemos contener una imagen (o un vídeo, ilustración o bloque de código) en un elemento y relacionarlo con un contenido concreto:

Alternative text Bruce and Remy welcome questions Photo £copy; Bruce's mum

En conveniente recordar que el atributo a1t indica el texto a mostrar cuando la imagen no está disponible, y no está pensada para contener una descripción de la imagen, y mucho menos para duplicar lo ya indicado en la etiqueta

. Ejercicio 1 Ver enunciado 2.5 ATRIBUTOS GLOBALES HTML5 también incluye nuevos atributos globales que pueden ser asignados a cualquier elemento. Son los siguientes: 2.5.1 ACCESSKEY El atributo accesskey permite a los desarrolladores especificar un atajo de teclado que permite activar un elemento a asignarle el foco. Este atributo ya existía en HTML 4, aunque ha sido utilizado en muy pocas ocasiones. Como HTML5 está pensado para aplicaciones, y algunos usuarios siguen prefiriendo los atajos de teclado, este atributo no ha sido eliminado, y ahora está disponible para cualquier elemento. Para evitar conflictos con otros atajos de teclado, o con los propios del navegador, ahora esta etiqueta permite asignar alternativas en este atributo. Un ejemplo incluido en la especificación: Esto quiere decir que este elemento es accesible a través de dos atajos de teclado, a través de la tecla s o a través de la tecla 0 (en ese orden). 2.5.2 CONTENTEDITABLE Inventado por Microsoft, e implementado por el resto de los navegadores, la etiqueta contenteditable es ahora parte de la especificación oficial. La introducción de esta etiqueta significa principalmente dos cosas: e Primero, los usuarios pueden editar los contenidos de un elemento que incluya esta etiqueta. Este elemento debe ser seleccionable y el navegador debe proporcionar una marca que indique la posición actual del cursor. e Y segundo, es posible cambiar el formato del texto del contenido, añadiendo negritas, cambiar la fuente, añadir listas, etc. Este atributo es de tipo booleano, por lo que su valor puede ser true o false. Al acceder desde JavaScript a este atributo, hay que tener en cuenta su notación lowerCamelCase, siendo el nombre de la propiedad del DOM contentEditable. Además, existe otra propiedad llamada isContentEditable, que indica si el elemento es editable o no.

Finalmente, el contenido que ha sido seleccionado por el usuario, puede ser objeto de modificaciones, como hemos comentado antes. A través del comando lement .execCommand () es posible indicar el tipo de modificación (poner en negrita, copiar, cambiar la fuente...), siempre que el documento se haya indicado como editable. document .designMode = 'on'; Si se desea almacenar los cambios realizados en el contenido, es necesario enviarlo al servidor. No existe ningún API o método en JavaScript que nos posibilite esta acción, por lo que debemos utilizar algún tipo de tecnología tipo AJAX. 2.5.3 DATA-* (CUSTOM DATA ATTRIBUTES) HTML5 permite crear atributos personalizados para los elementos. Estos atributos son utilizados para pasar información a JavaScript. Como veremos en el capítulo correspondiente, hasta ahora se utilizaba el atributo class para de alguna manera almacenar información asociada con elementos, pero esto cambia radicalmente con estos atributos.

<1li data-spacing="10cm" data-sowing-time="March to June">Carrots1i>

Celery1li>

Radishes1i> 2.5.4 DRAGGABLE Este atributo indica que el elemento indicado puede ser arrastable. Lo veremos en el capítulo correspondiente. ÍNDICE DE CONTENIDOS Semántica 2.1 Cabecera del documento 2.2 Nuevas etiquetas semánticas 2.3 Estructura de un documento HTML5 2.4 Uso de las nuevas etiquetas semánticas 2.5 Atributos globales

— Anterior Siguiente => CAPÍTULO 3 ELEMENTOS DE FORMULARIO HTML5 hace que el desarrollo de formularios sea mucho más sencillo. Se han añadido dos nuevos métodos que pueden ser utilizados en la acción del formulario (update y delete), pero lo más interesante son los nuevos tipos de input y elementos de formulario que mejoran la experiencia del usuario y facilitan el desarrollo de los formularios. Estos nuevos elementos añaden en algunos casos, validaciones propias de sus datos, por lo que ya no es necesario JavaScript para realizar este proceso. 3.1 NUEVOS TIPOS DE INPUT La especificación de HTML5 define 12 nuevos tipos de input que podemos utilizar en nuestros formularios. Esta especificación no define cómo deben mostrarse los nuevos tipos en los navegadores, ni los campos ni las validaciones. De hecho, y gracias a cómo está especificado HTML, los navegadores que no comprendan los nuevos tipos de entrada, mostrarán un campo de texto tradicional, por lo que la compatibilidad con navegadores antiguos está garantizada. 3.1.1 TIPO EMAIL El nuevo tipo indica al navegador que no debe permitir que se envíe el formulario si el usuario no ha introducido una dirección de email válida, pero no comprueba si la dirección existe o no, sólo si el formato es válido. Como ocurre con el resto de campos de entrada, puede enviar este campo vacío a menos que se indique que es obligatorio. El atributo multiple indica que el valor de este campo, puede ser una lista de emails válidos, separados por comas.

10:37 AM 0/u|e]a]1|v]u]:]o]e aJs]o]=]o]«[s]x]i 2 BOG0000 + >< Te] JE Figura 3.1 Campo de tipo emai1 en un dispositivo ¡OS 3.1.2 TIPO URL El nuevo tipo indica al navegador que no debe permitir que se envíe el formulario si el usuario no ha introducido una URL correcta. Algunos navegadores ofrecen ayudas al usuario, como Opera que añade el prefijo http: // a la URL si el usuario no lo ha introducido. Una URL no tiene que ser necesariamente una dirección web, sino que es posible utilizar cualquier formato de URI válido, como por ejemplo talco Saa.

10:39 AM ojw|ejeT[vju]1jojr ajsjojrfafu[sfk je zp xjo]vfs[n]mio MEE. Figura 3.2 Campo de tipo uri en un dispositivo ¡OS 3.1.3 TIPO DATE El nuevo tipo es de los más esperados y útiles. En muchos de los sitios web es normal disponer de campos específicos de fecha, donde el usuario debe especificar fechas (para un concierto, vuelo, reserva de hotel, etc). Al existir tantos formatos de fecha diferentes (DD-MM-YYYY o MM-DD-YYYY o YYYY-MM-DD), esto puede suponer un inconveniente para los desarrolladores o los propios usuarios. Este nuevo tipo de campo resuelve estos problemas, ya que es el navegador el que proporciona la interfaz de usuario para el calendario, e idependientemente del formato en el que se muestre, los datos que se envían al servidor cumplen la norma ISO para el formato de fechas.

Carrier = 10:40 AM CIAO Cu Date: | May 14, 2013%y Clear Done Figura 3.3 Campo de tipo date en un dispositivo ¡OS 3.1.4 TIPO TIME El nuevo tip0 permite introducir una hora en formato 24h, y validarlo. De nuevo, es el navegador el encargado de mostrar la interfaz de usuario correspondiente: puede ser un simple campo donde es posible introducir la hora y los minutos, o mostrar algo más complejo como un reloj de agujas.

10:41 AM Time: Clear Done Figura 3.4 Campo de tipo time en un dispositivo ¡OS 3.1.5 TIPO DATETIME Este nuevo tipo de campo es la combinación de los tipos date y time, por lo que se valida tanto la fecha como la hora introducida.

Carrier = 10:42 AM cm May 14, 2013, 10:37 AMP Clear Done Mon May 13| 9 |36 ali da lenin! inn ¡ia vo o Figura 3.5 Campo de tipo datetime en un dispositivo ¡OS 3.1.6 TIPO MONTH El nuevo tipo permite la selección de un mes en concreto. La representación interna del mes es un valor entre 1 y 12, pero de nuevo queda en manos del navegador la manera de mostrarlo al usuario, utilizando los nombres de los meses por ejemplo.

Carrier = 10:42 AM file://Volumes/dev_src on Clear Done Figura 3.6 Campo de tipo month en un dispositivo ¡OS 3.1.7 TIPO WEEK El nuevo tipo permite la selección de una semana del año concreta. La representación interna del mes es un valor entre 1 y 53, pero de nuevo queda en manos del navegador la manera de mostrarlo al usuario. La representación interna de la semana 7, por ejemplo, es la siguiente: 2013-07.

€ -— (|) [| ww.arkaitzgarro.com 600 ); | Nuevos tipos de input x WI Week: ISemana ES, (Y | Enviar | id E mayo de 2013 » mi » mar mié jue A -2 Esta semana | Eliminar | Figura 3.7 Campo de tipo week en Google Chrome 3.1.8 TIPO NUMBER Como es de esperar, el nuevo tipo valida la entrada de un tipo de dato numérico. Este tipo de campo encaja perfectamente con los atributos min, max Y step, que veremos más adelante. MUEVO: Lua tipos de input. file://Wolumes/dev_src/. C) | Search) +J2]3/4]5/0/7]0]] S006000006 S- 1771 TE JE

Figura 3.8 Campo de tipo number en un dispositivo ¡OS 3.1.9 TIPO RANGE El nuevo tipo , muestra un control deslizante en el navegador. Para conseguir un elemento de este estilo, era necesario un gran esfuerzo para combinar imágenes, funcionalidad y accesibilidad, siendo ahora mucho más sencillo. Este tipo de campo encaja de nuevo perfectamente con los atributos min, max Y step, que veremos más adelante. ed e0.00 Nuevos tipos de input x Ye € CO. [% www.arkaitzgarro.com Range: Enviar Figura 3.9 Campo de tipo range en Google Chrome 3.1.10 TIPO TEL El nuevo tipo , espera que se proporcione un número de teléfono. No se realiza ninguna validación, ni se obliga a que únicamente se proporcionen caracteres numéricos, ya que un número de teléfono puede representarse de muchas maneras: +44 (0) 208 123 1234. La gran ventaja de este campo es que en dispositivos con un teclado virtual, éste se adaptará para mostrar únicamente los caracteres asociados on números de teléfono.

Figura 3.10 Campo de tipo tel en un dispositivo ¡OS 3.1.11 TIPO SEARCH El nuevo tipo , espera que se proporcione un término de búsqueda. La diferencia con un campo de texto normal, es únicamente estética, aunque puede ofrecer alguna funcionalidad extra como un histórico de últimos términos introducidos o una ayuda para el borrado. Por norma general, toma el aspecto de un campo de búsqueda del navegador o sistema operativo. e00 y |] Nuevos tipos de input x Wi A : 4 a] . ñ _ € -— (1) |) wmw.arkaitzgarro.com Search: ' htmis 3) | Enviar |

Figura 3.11 Campo de tipo search en Google Chrome 3.1.12 TIPO COLOR El nuevo tip0 , permite seleccionar un color de una paleta de colores mostrada por el navegador. Esta paleta de colores, coincide, por norma general, con la interfaz de selección de colores del sistema operativo. A e00 Nuevos tipos de input x W e € CC [1% www.arkaitzgarro.com = Color: o] | Enviar Figura 3.12 Campo de tipo color en Google Chrome 3.2 NUEVOS ATRIBUTOS Al igual que los nuevos tipos de campo, el elemento input ha recibido nuevos atributos para definir su comportamiento y restricciones: autocomplete, min, max, multiple, pattern, autofocus, placeholder, required Y step. Existe además un nuevo atributo, list, que hace referencia a otro elemento, permitiendo crear un nuevo tipo de entrada de datos. 3.2.1 ATRIBUTO Mim Y Eneas La combinación del atributo 1ist y un elemento de tipo da como resultado un campo de texto, donde el usuario puede introducir cualquier contenido, y las opciones definidas en el se muestran como una lista desplegable. Hay que tener en cuenta que la lista tiene que estar contenida en un elemento Cuyo

id coincide con el indicado en el atributo list:

En este ejemplo se utiliza un campo de tipo text, pero puede ser utilizado igualmente con campos de tipo url y email. A e. Nuevo elemento datalist É fe C'- [) www.arkaitzgarro.com = al Surf ka Dev uo Scrum Ll Mobile » al Otros marcadores Enviar Mr Ms | Mad Professor — Prof Figura 3.13 Nuevo elemento datalist, asociado a un campo de texto 3.2.2 ATRIBUTO AUTOFOCUS El atributo booleano autofocus permite definir que control va a tener el foco cuando la página se haya cargado. Hasta ahora, esto se conseguía a través de JavaScript, utilizando el método .focus() en un elemento concreto, al cargarse el documento. Ahora es el navegador el encargado de esta tarea, y puede comportarse de manera más inteligente, como no cambiando el foco de un elemento si el usuario ya se encuentra escribiendo en otro campo (éste era un problema común con JavaScript). Únicamente debe existir un elemento con este atributo definido en el documento. Desde el punto de vista de la usabilidad, hay que utilizar este atributo con cuidado. Hay que utilizarlo únicamente cuando el control que recibe el foco es el elemento principal de la página, como en un buscador, por ejemplo. 3.2.3 ATRIBUTO PLACEHOLDER Una pequeña mejora en la usabilidad de los formularios, suele ser colocar un pequeño texto de ayuda en algunos campos, de manera discreta y que desaparece cuando el

usuario introduce algún dato. Como con el resto de elementos, hasta ahora era necesario utilizar JavaScript para realizar esta tarea, pero el atributo placeholder resuelve esta tarea. Es importante recordar que este atributo no sustituye a la etiqueta . e00 / |) Atributo placeholder x N e € 3 (> | ww.arkaitzgarro.com = (Surf (Dew (Scrum (] Mobile » [7 Otros marcadores Search: | Enviar | Figura 3.14 Atributo placeholder en un campo de búsqueda 3.2.4 ATRIBUTO REQUIRED Este atributo puede ser utilizado en un y en la gran mayoría de los elementos <input/> (excepto en los de tipo hidden, image O botones Como submit). Cuando este atributo está presente, el navegador no permite el envío del formulario si el campo en concreto está vacío. e00 Atributo required x WN E € 3 (> |) ww.arkaitzgarro.com = al Surf al Dev Q Scrum (a Mobile » ll Otros marcadores Name [JC tnvar (Y Completa este campo Figura 3.15 Atributo required en un campo de texto

3.2.5 ATRIBUTO MULTIPLE Este atributo permite definir que un campo puede admitir varios valores, como URLs o emails. Un uso muy interesante de este atributo es utilizarlo en conjunto con el campo , ya que de esta manera nos permite seleccionar varios ficheros que podemos enviar al servidor al mismo tiempo. 3.2.6 ATRIBUTO AUTOCOMPLETE Algunos navegadores suelen incluir alguna funcionalidad de autocompletado en algunos campos de formulario. A pesar de haber sido introducido recientemente en el estándar de HTML5, es una característica que lleva mucho tiempo siendo utilizada, concretamente desde la versión 5 de Internet Explorer. Este atributo permite controlar el comportamiento del autocompletado en los campos de texto del formulario (que por defecto está activado). 3.2.7 ATRIBUTOS MIN Y MAX Como hemos visto en el campo , estos atributos restringen los valores que pueden ser introducidos; no es posible enviar el formulario con un valor menor que min o un valor mayor que max. También es posible utilizarlo en otro tipo de campos como date, para especificar fechas mínimas o máximas. e08e Atributos min y max x s € C [| wwwarkaitzgarro.com = ll Surf [mem Dev al Scrum (a Mobile » ka Otros marcadores Name: 11] (+)' | Enviar [1] El valor debe inferior o igual a 10 Figura 3.16 Atributos min y max en un campo numérico 3.2.8 ATRIBUTO STEP

El atributo step controla los pasos por los que un campo aumenta o disminuye su valor. Si un usuario quiere introducir un porcentaje, pero queremos que sea en múltiplos de 5, lo haríamos de la siguiente manera: 3.2.9 ATRIBUTO PATTERN Algunos de los tipos de input que hemos visto anteriormente (email, number, url...), son realmente expresiones regulares que el navegador evalúa cuando se introducen datos. El atributo pattern nos permite definir una expresión regular que el valor del campo debe cumplir. Por ejemplo, si el usuario debe introducir un número seguido de tres letras mayúsculas, podríamos definir esta expresión regular: La especificación indica que la sintaxis de la expresión regular que utilicemos debe coincidir con la utilizada en JavaScript. 3.2.10 ATRIBUTO Form Tradicionalmente, los campos de un formulario van incluidos dentro de la correspondiente etiqueta

. Si por la razón que fuese (principalmente diseño) un elemento tuviese que mostrarse apartado del resto de elementos del formulario, se hacía casi necesario incluir toda la página dentro de una etiqueta

. Con HTML5, los elementos que hasta ahora era obligatorio que estuviesen contenidos dentro del elemento

, pueden colocarse en cualquier lugar de la página, siempre que los relacionemos con el formulario concreto a través del atributo form y el ia de dicho formulario. < TEO mMitad= Oo

En este caso, el elemento se encuentra fuera del formulario, pero realmente pertenece a él ya que hemos definido el atributo form con el identificador del formulario. 3.3 NUEVOS ELEMENTOS Además de los nuevos tipos de input incluidos en la especificación, se han añadido nuevos elementos de formulario, entre los que se incluyen los siguientes:

3.3.1 El elemento es utilizado para representar un avance o progreso en la ejecución de una tarea, como puede ser la descarga de un fichero o la ejecución de una tarea compleja. Define los siguientes atributos: e max: define el trabajo total a realizar por la tarea, la duración de un vídeo... Su valor por defecto es 1.0. e value: el valor actual (en coma flotante) o estado del progreso. Su valor debe ser mayor o igual a 0.0 y menor o igual a 1.0 o el valor especificado en max. e position: atributo de sólo lectura que representa la posición actual del elemento . Este valor es igual a value/max y -1 si no se puede determinar la posición. Las unidades son arbitrarias, y no se especifican. 5 e... |] Nuevo elemento progress * deca e” € C'- [% www.arkaitzgarro.com = (] Surf (Dev [Scrum (] Mobile » [2] Otros marcadores — —Figura 3.17 Nuevo elemento progress 3.3.2 El elemento es muy similar a (de hecho, se discute la necesidad de disponer de dos elementos tan similares). Esta nueva etiqueta se usa para representar escalas de medidas conocidas, como la longitud, masa, peso, uso de disco, entre otras. Define los siguientes atributos: e value: representa el valor actual. Si no se especifica, se toma como valor el primer número que aparece en el contenido del elemento. Su valor por defecto es 0. e min: el mínimo valor permitido. El valor por defecto es 0.

e max: el mayor valor permitido. Si no se especifica, su valor por defecto es 1, a menos que el valor mínimo definido sea mayor que 1, en cuyo caso el valor de max será igual a min. e low: es considerado el límite inferior del rango de valores. e max: es considerado el límite superior del rango de valores. e optimum: representa el valor óptimo del elemento, y se encuentra entre min y max.

Your score 1s: A+ > e... / | Nuevo elemento meter x E C- [5 wwwarkaitzgarro.com = (7 Surf (Dew (Scrum (2 Mobile » [7 Otros marcadores Y our score is: Figura 3.18 Nuevo elemento meter Ejercicio 2 Ver enunciado ÍNDICE DE CONTENIDOS Elementos de formulario 3.1 Nuevos tipos de input 3.2 Nuevos atributos 3.3 Nuevos elementos

— Anterior Siguiente => CAPÍTULO 4 QUÉ ES MODERNIZR Modernizr es una librería JavaScript que nos permite conocer la compatibilidad del navegador con tecnologías HTML5 y CSS3, lo que nos permitirá desarrollar sitios web que se adapten a las capacidades cada navegador. Este framework es un paquete de detección de las capacidades de un navegador relativas a HTML5 y CSS3, esto es, una librería JavaScript que nos informará cuáles de las funcionalidades de estas tecnologías están disponibles en el navegador del usuario, para utilizarlas, o no, en cada caso. Sabiendo que nuestro navegador soporta ciertas capacidades de CSS3 o de HTML5, podremos utilizarlas con libertad. De modo contrario, si sabemos que un navegador no es compatible con determinada funcionalidad, podremos implementar variantes que sí soporte y así crear sitios web que se adaptan perfectamente al cliente web de cada visitante. Existen dos herramientas principales en Modernizr que se pueden utilizar para detectar las funcionalidades que están presentes en un navegador. Una la podemos utilizar a través de JavaScript y otra directamente sobre código CSS. En resumen, con Modernizr podemos detectar las funcionalidades disponibles de CSS3 y HTML5. 4.1 AÑADIR MODERNIZR A UNA PÁGINA El primer paso consistirá en descargar el archivo con el código fuente de Modernizr. Se trata de un archivo con código JavaScript que podemos encontrar en dos variantes: e. Development: contiene el código fuente completo, sin comprimir y con comentarios. Debemos utilizar esta variante únicamente en desarrollo o cuando queremos acceder a su código, para comprenderlo o ampliarlo. e Production: es recomendable (o más bien obligatorio) utilizar esta variante cuando pasamos a un entornos de producción. Al descargarnos Modernizr, tenemos la posibilidad de generar una librería únicamente con las funcionalidades que queremos detectar, lo que nos permitirá ahorrarnos una importante cantidad de kB innecesarios. Una vez que hemos descargado nuestra librería, debemos incluirla en el código HTML de la página, de la misma manera que incluimos scripts JavaScript.

Según podemos leer en la documentación de Modernizr, se aconseja colocar el script dentro del HEAD, porque debe cargarse antes del BODY de la página, debido a un componente que quizás utilicemos, para permitir HTML5 en Internet Explorer, llamado HTML5 Shiv. Además, se recomienda colocarlo después de los estilos CSS para evitar un comportamiento poco deseable llamado FOUC, por el cual puede mostrarse, por un pequeño espacio de tiempo, la página sin los estilos CSS aplicados. A partir de este momento tendremos disponibles nuestros scripts de detección de funcionalidades así como una serie de clases CSS que nos ayudarán a aplicar estilos solo cuando los navegadores los soporten. 4.2 OBJETO MODERNIZR Cuando tenemos Modernizr cargado en nuestra página, se crea automáticamente un objeto JavaScript que tiene una serie de propiedades que nos indican si están o no disponibles cada una de las funcionalidades presentes en CSS3 y HTML5. Las mencionadas propiedades contienen simplemente valores booleanos (true o false) que podemos consultar para saber si están o no disponibles las funcionalidades que deseamos utilizar. El uso es tan sencillo como se indica a continuación: if (Modernizr.boxshadow) ( // Podemos aplicar sombras! + else ( // La propiedad box-shadow no está disponible Aquí estamos consultando la propiedad boxshadow del objeto Modernizr. Esta propiedad nos indica si el navegador es compatible con el atributo box-shadow de CSS3, que sirve para crear cajas de contenido con sombreado. Ahora veamos otro ejemplo similar que detectaría si está disponible el elemento canvas del HTML5. if (Modernizr.canvas) ( // Podemos utilizar canvas! + else ( // El elemento canvas no está disponible Este es un simple ejemplo que comprueba si están disponibles ciertas propiedades y funcionalidades de CSS3 y HTML5. Lógicamente, tendremos que desarrollar las funcionalidades que correspondan en cada caso. El listado completo de propiedades del

objeto para la detección de funcionalidades HTML5 y CSS3 se puede encontrar en la propia documentación de Modernizr. 4,3 CLASES CSS EN MODERNIZR Cuando tenemos Modernizr cargado en nuestra página, éste crea automáticamente una serie de clases que asigna al elemento htmi1 del documento. Cada una de estas clases hace referencia a las características que soporta el navegador, permitiendo desde CSS adaptar la interfaz según las funcionalidades. Un ejemplo de las clases que crea en un navegador de escritorio moderno:

Todo el proceso es automático y la creación de cada una de esas clases se realizará únicamente en caso de que el navegador sea compatible con cada una de las características de CSS3 y HTML5. La manera de utilizar estas clases es muy sencilla. Pensemos en que queremos aplicar sombra a un elemento con CSS3 en los navegadores que lo permitan y emular ese sombreado por medio de estilos CSS clásicos en los navegadores que no soporten el atributo box-shadow. Lo único que tenemos que hacer es aplicar los estilos clásicos al elemento que deseemos: .elementofÍ border-left: 1lpx solid +$ccc; Pbornder=topea px esoltia eee, border-bottom: 1lpx solid +666; border-right: 1lpx solid +666; Posteriormente, si nuestro navegador es compatible con el atributo box-shadow de CSS3, Modernizr habrá incluido la clase "boxshadow" en el elemento html. Nosotros podemos

utilizar dicha clase CSS para aplicar estilos que sabemos que solo acabarán afectando a los navegadores que soporten el atributo box-shadow. .boxshadow .elemento(fÍ border: 1lpx solid $ccc; Loxa do DOES ES OS Ox Como se puede ver, hemos sobrescrito la regla CSS para el borde y además hemos aplicado la propiedad box-shadow. El efecto conseguido es que los navegadores modernos, que son capaces de procesar el atributo box-shadow, mostrarán una sombra CSS3 y los no compatibles con esta propiedad al menos mostrarán unos estilos para los que sí son compatibles. Ejercicio 3 Ver enunciado 4.4 EL MÉTODO LOAD () El método Modernizr.load() es una sencilla manera para cargar librerías sólo cuando los usuarios las necesitan, es decir, cuando una funcionalidad en concreto está (o no) disponible. Es una buena manera de ahorrar ancho de banda y mejorar un poco más el rendimiento de la aplicación. Por ejemplo, pensemos en que estamos desarrollando una aplicación basada en el API de geolocalización de HTML5. Con Modernizr podemos saber si el navegador ofrece soporte a ese API, mediante la propiedad Modernizr.geolocation. Si deseamos cargar unos recursos u otros dependiendo de la disponibilidad de esta funcionalidad, el método Modernizr.load() nos podrá ahorrar algo de código fuente y de paso acelerar nuestra página en algunas ocasiones. Con éste método podemos indicar a los navegadores que no soporten ese API que carguen el polyfill correspondiente, de modo que se pueda utilizar esa característica de HTML5 en ellos también. La sintaxis de Modernizr.load() es bastante sencilla de comprender. Un ejemplo sencillo: Modernizr.load(( test: Modernizr.geolocation, VENIS OS nope: 'geo-polyfi11l.]3s' 10% En este ejemplo, se decide que script se debe cargar, en función de si la geolocalización esta soportada por el navegador o no. De esta manera, nos ahorramos el tener que

descargar código que el navegador no soporta y por lo tanto, no necesita. Modernizr.load() es simple y eficaz, pero podemos utilizarlo de manera más compleja, como se muestra en el siguiente ejemplo: // Give Modernizr.load a string, an object, or an array of strings and objects Modernizr.load (ll // Presentational polyfills [ // Logical list of things we would normally need test : Modernizr.fontface £s£ Modernizr.canvas £s Modernizr.cssgradients, // Modernizr.load loads css and javascript by default nope : ['presentational-polyfill.js', 'presentational.css'] h, Enero polytalie [ AMS Susa dass ES las ierebiciay test : Modernizr.websockets ££8 window.JSON, If Socio) 38 eme sona. ye moje s “iEnaecralcasl>90 ly ls: 38%, // You can also give arrays of resources to load. Soma E [aga el, "extras! 1, complete : function () ( // Run this after everything in this group has downloaded // and executed, as well everything in all previous groups myApp. init (); p, // Run your analytics after you've already kicked off all the rest VIDEO DE ELO asar =emallyicles e 11 Ejercicio 4 Ver enunciado ÍNDICE DE CONTENIDOS Qué es Modernizr 4.1 Añadir Modernizr a una página 4.2 Objeto Modernizr 4.3 Clases CSS en Modernizr 4.4 El método loaa()

— Anterior Siguiente => CAPÍTULO 5 DATASET Gracias a HTML5, ahora tenemos la posibilidad de incorporar atributos de datos personalizados en todos los elementos HTML. Hasta la aparición de estos atributos, la manera de lograr un comportamiento similar (asociar datos a elementos), era incluir estos datos como clases CSS en los elementos, y acceder a ellos a través de ¡Query, de una manera como la siguiente: Una vez definidos los "atributos", era necesario acceder a estas clases y realizar un trabajo extra para extraer su nombre y su valor (convertir energy-75en energy = 75). Afortunadamente, esto ya no es necesario, gracias a los atributos dataset. Estos nuevos atributos de datos personalizados constan de dos partes: e Nombre del atributo: el nombre del atributo de datos debe ser de al menos un carácter de largo y debe tener el prefijo data-. No debe contener letras mayúsculas. e Valor del atributo: el valor del atributo puede ser cualquier string o cadena. Con esta sintaxis, podemos añadir cualquier dato que necesitemos a nuestra aplicación, como se muestra a continuación:

<1li data-spacing="10cm" data-sowing-time="March to June">Carrots1i> <1li data-spacing="30cm" data-sowing-time="February to March">Celery1li>

Radishes1i> Ahora podemos usar estos datos almacenados en nuestro sitio para crear una experiencia de usuario más rica y atractiva. Imagina que cuando un usuario hace clic en un "vegetable", una nueva capa se abre en el explorador que muestra la separación de semillas e instrucciones de siembra. Gracias a los atributos data- que hemos añadido a nuestros elementos <1i>, ahora podemos mostrar esta información al instante sin tener que preocuparnos de hacer ninguna llamada asJax y sin tener que hacer ninguna consulta a las bases de datos del servidor. Prefijar los atributos personalizados con data- asegura que van a ser completamente ignorados por el agente de usuario. Por lo que al navegador y al usuario final de la web se refiere, no existe esta información.

Custom data attributes are intended to store custom data private to the page or application, for which there are no more appropriate attributes or elements. These attributes are not intended for use by software that is independent of the site that uses the attributes. Every HTML element may have any number of custom data attributes specified, with any value. W3C Specification Esto es, los atributos de datos personalizados están destinadas a almacenar los datos personalizados que son de interés exclusivamente para la página o la aplicación, para los que no hay atributos o elementos más apropiados. Estos atributos no están destinados para un uso externo (a través de un software independiente al sitio que los utiliza). Cada elemento HTML puede tener un número indefinido de atributos de datos personalizados, con cualquier valor. 5.1 UTILIZACION DE LOS DATA ATTRIBUTES Como los atributos de datos personalizados son válidos en HTML5, pueden ser utilizados en cualquier navegador que soporte HTML5 doctypes. Estas son algunas de las formas en las que pueden ser utilizados: e Para almacenar la altura inicial o la opacidad de un elemento que pudiera ser necesaria en los cálculos de animación JavaScript posteriores. e Para almacenar los parámetros para una película de Flash que se carga a través de JavaScript. e Para almacenar los datos estadísticos de una web. e Para almacenar los datos acerca de la salud, munición o vida de un elemento en un juego JavaScript. e Para poder añadir subtítulos a un . Y éstas algunas de las situaciones para las que no se deben usar los data attributes: e Los atributos de datos personalizados no deben usarse si hay un atributo o elemento existente que es más adecuado. e Éstos tampoco tienen la intención de competir con microformatos. En la especificación queda claro que los datos no están pensados para ser usados públicamente. El software externo no debe interactuar con ellos. e La presencia/ausencia de un atributo de datos personalizado no se deben utilizar como una referencia para los estilos de CSS. Si se hace, podría sugerir que los datos que se están almacenando son de importancia inmediata para el usuario y se deberían marcar de una manera más accesible.

5.2 DATA ATTRIBUTES Y JAVASCRIPT Ahora que comprendemos el funcionamiento de los atributos de datos personalizados y cuándo se utilizan, deberíamos centrarnos en cómo interactuar con ellos utilizando JavaScript. Si quisiéramos recuperar o actualizar estos atributos utilizando JavaScript, podríamos hacerlo utilizando los métodos getAttribute Y setAttribute.

ISC ES data-attributes using getAttribute var plant = document .getElementByld ("strawberry-plant"); var fruitCount = plant.getAttribute("data-fruit"); // fruitCount = "12" // "Setting" data-attributes using setAttribute planes erario datar O SiS tros SCA Este método funcionará en todos los navegadores modernos, pero no es la manera en la que los data attributes deben ser utilizados. La mejor manera para lograr lo mismo es mediante el acceso a la propiedad dataset de un elemento. Al utilizar este método, en lugar de utilizar el nombre del atributo completo, se puede prescindir del prefijo data- y referirse a los atributos de datos personalizados utilizando directamente los nombres que se han asignado.

// "Getting" data-attributes using dataset var plant = document .getElementByld ("sunflower"); vals aves planta aras SS aves Se SI // "Setting" data-attributes using dataset var tallness = plant.dataset.plantHeight; // "plant-height" -> "plantHeight" plant.dataset.plantHeight = "3.6m"; // Cracking fertiliser Si en algún momento un atributo data- específico ya no es necesario, es posible eliminarlo por completo del elemento DOM estableciendo un valor nulo. plant.dataset.leaves = null; En conclusión, los data attributes personalizados son una buena manera de simplificar el

almacenamiento de datos de la aplicación en las páginas web. Ejercicio 5 Ver enunciado ÍNDICE DE CONTENIDOS Dataset 5.1 Utilización de los data attributes 5.2 data attributes y JavaScript

— Anterior Siguiente => CAPÍTULO 6 MULTIMEDIA Hasta hace no mucho tiempo, la tecnología Flash era el dominador indiscutible en el campo multimedia de la web. Gracias a esta tecnología es relativamente sencillo transmitir audio y vídeo a través de la red, y realizar animaciones que de otra manera sería imposible. Prácticamente todos los navegadores tienen incorporado un plugin para la reproducción de archivos flash, por lo que la elección era clara. Entonces, ¿por qué una necesidad de cambio? Hasta ahora, para incluir un elemento multimedia en un documento, se hacía uso del elemento , cuya función es incluir un elemento externo genérico. Debido a la incompatibilidad entre navegadores, se hacía también necesario el uso del elemento y duplicar una serie de parámetros. El resultado era un código de este estilo: Dejando de lado que el código es poco amigable, en este caso tenemos el problema que el navegador tiene que transmitir el vídeo a un plugin instalado en el navegador, con la esperanza que el usuario tenga instalada la versión correcta o tenga permisos para hacerlo, y muchos otros requisitos que pueden ser necesarios. Los plugins pueden causar que el navegador o el sistema se comporte de manera inestable, o incluso podemos crear una inseguridad a usuarios sin conocimientos técnicos, a los que se pide que descarguen e instalen un nuevo software. De alguna manera, podemos estar creando una barrera para ciertos usuarios, algo que no es para nada deseable. 6.1 VÍDEO Una de las mayores ventajas del elemento (y ) de HTML5, es que, finalmente, están totalmente integrados en la web. Ya no es necesario depender de software de terceros, y esto es una gran ventaja.

Así que ahora, el elemento pueden personalizarse a través de estilos CSS. Se puede cambiar su tamaño y animarlo con transiciones CSS, por ejemplo. Podemos acceder a sus propiedades a través de JavaScript, transformarlos y mostrarlos en un . Y lo mejor de todo, es que podemos manipularlos con total libertad, ya que pertenecen al estándar. Ya no se ejecutan en una caja negra a la que no teníamos acceso. A pesar de que la etiqueta se presenta como una alternativa de flash, sus funcionalidades van mucho más allá, como veremos a continuación. 6.1.1 MARCADO Para hacer funcionar el vídeo en HTML, es suficiente con incluir el siguiente marcado, de manera similar que lo hacemos con las imágenes: < 1 MiOube jee locals COn tent here 6.1.3 CONTROLS Proporcionar controles es aproximadamente un 764% mejor que reproducir el vídeo de manera automática. La manera de indicar que se muestren los controles es la siguiente: Naturalmente, y al igual que ocurre con los campos de formulario, los navegadores

muestran los controles de manera diferente, ya que la especificación no indica qué aspecto deben tener. De todas maneras, independientemente del aspecto, todos ellos coinciden en los controles a mostrar: reproducir/pausa, una barra de progreso y un control de volumen. Normalmente, los navegadores esconden los controles, y solamente aparecen al mover el ratón sobre el vídeo al utilizar el teclado para controlar el vídeo. A e00 | y Controles de video x W Y € CO [5 wwwarkaitzgarro.com = A — A 029 q) ae Y Figura 6.1 Controles de vídeo en Google Chrome 6.1.4 POSTER El atributo poster indica la imagen que el navegador debe mostrar mientras el vídeo se está descargando, o hasta que el usuario reproduce el vídeo. Esto elimina la necesidad de mostrar una imagen externa que después hay que eliminar con JavaScript. Si no se indica este atributo, el navegador muestra el primer fotograma del vídeo, que puede no ser representativo del vídeo que se va a reproducir.

900 7 [> controles de video x e C- |” wwwarkaitzgarro.com Figura 6.2 Fotograma poster del vídeo anterior 6.1.5 MUTED El atributo muted, permite que el elemento multimedia se reproduzca inicialmente sin sonido, lo que requiere una acción por parte del usuario para recuperar el volumen. En este ejemplo, el vídeo se reproduce automáticamente, pero sin sonido: 6.1.6 HEIGHT, WIDTH Los atributos height y width indican al navegador el tamaño del vídeo en pixels. Si no se indican estas medidas, el navegador utiliza las medidas definidas en el vídeo de origen, si están disponibles. De lo contrario, utiliza las medidas definidas en el fotograma poster, si están disponibles. Si ninguna de estas medidas está disponible, el ancho por defecto es de 300 pixels. Si únicamente se especifica una de las dos medidas, el navegador automáticamente ajusta la medida de la dimensión no proporcionada, conservando la proporción del vídeo. Si por el contrario, se especifican las dos medidas, pero no coinciden con la proporción del vídeo original, el vídeo no se deforma a estas nuevas dimensiones, sino que se muestra en formato letterbox manteniendo la proporción original.

6.1.7 LOOP El atributo loop indica que el vídeo se reproduce de nuevo una vez que ha finalizado su reproducción. 6.1.8 PRELOAD Es posible indicar al navegador que comience la descarga del vídeo antes de que el usuario inicie su reproducción. < Existen tres valores definidos para preload. Si no indicamos uno en concreto, es el propio navegador el que decide qué hacer. Por ejemplo, en un dispositivo móvil, el comportamiento por defecto es no realizar ninguna descarga hasta que el usuario lo haya indicado. Es importante recordar que un desarrollador no puede controlar el comportamiento de un navegador: preload es un consejo, no un comando. El navegador tomará una decisión en función del dispositivo, las condiciones de la red y otros factores. e preload=auto: se sugiere al navegador que comience la descarga. e preload=none: se sugiere al navegador que no comience la descarga hasta que lo indique el usuario. e preload=metadata: este estado sugiere al navegador que cargue los metadatos (dimensiones, fotogramas, duración...), pero no descarga nada más hasta que el usuario lo indique. 6.1.9 SRC Al igual que en elemento , el atributo src indica la localización del recurso, que el navegador debe reproducir si el navegador soporta el codec o formato específico. Utilizar un único atributo src es únicamente útil y viable en entornos totalmente controlados, donde conocemos el navegador que accede al sitio web y los codecs que soporta. Sin embargo, como no todos los navegadores pueden reproducir los mismos formatos, en entornos de producción debemos especificar más de una fuente de vídeo. 6.2 CODECS, LA NUEVA GUERRA En los primeros borradores de la especificación de HTML5, se indicaba que se debía de ofrecer soporte para al menos dos codecs multimedia: Ogg Vorbis para audio y Ogg Theora para vídeo. Sin embargo, estos requisitos fueron eliminados después de que Apple y Nokia se opusieran, de modo que la especificación no recomendase ningún codec en concreto. Esto ha creado una situación de fragmentación, con diferentes

navegadores optando por diferentes formatos, basándose en sus ideologías o convicciones comerciales. Actualmente, hay dos codecs principales que debemos tener en cuenta: el nuevo formato WebM, construido sobre el formato VP8 que Google compró y ofrece de manera libre, y el formato MP4, que contiene el codec propietario H.264. WEBM MP4 OGV Opera SÍ No SÍ Firefox SÍ Si SÍ Chrome SÍ No Si 1E9+ No SÍ No Safari No SÍ No WebM funciona en 1E9+ y Safari si el usuario ha instalado los codec de manera manual. Por lo tanto, la mejor solución en estos momentos es ofrecer tanto el formato libre WebM, como el propietario H.264. 6.2.1 MULTIPLES ELEMENTOS Para poder ofrecer ambos formatos, primeramente debemos codificarlos por separado. Existen diversas herramientas y servicios on-line para realizar esta tarea, pero quizás el más conocido sea Miro Video Converter. Este software, disponible para Windows y Mac, nos permite convertir los vídeos en formato Theora, o H.264 (y muchos otros) optimizados para diferentes tipos de dispositivos como iPhone, Android, PSZ2, etc. Una vez dispongamos el vídeo en los distintos formatos, es necesario indicar todas las localizaciones de estos formatos, para que sea el navegador el que decida que formato reproducir. Evidentemente, no podemos especificarlos todos dentro del atributo scr, por lo que tendremos que hacerlo de manera separada utilizando el elemento . webM or MP4 format.

6.2.2 MEDIA QUERIES PARA VIDEO Los ficheros de vídeo tienden a ser pesados, y enviar un vídeo en alta calidad a un dispositivo con un tamaño de pantalla reducido es algo totalmente ineficiente. No hay ningún inconveniente en hacerlo, pero si comprimimos el vídeo y disminuimos sus dimensiones, conseguiremos reducir su tamaño (en MB), algo de agradecer en entornos móviles y que dependen de una conexión de datos. HTML5 permite utilizar el atributo media en el elemento , ofreciendo la misma funcionalidad que los Media Queriesen CSS3. Por lo tanto, podemos consultar al navegador por el ancho de la pantalla, la relación de aspecto, colores, etc, y definir el video correcto según las características del dispositivo. 6.3 API MULTIMEDIA Los elementos multimedia y ofrecen un API JavaScript muy completo y fácil de utilizar. Los eventos y métodos de los elementos de audio y vídeo son exactamente los mismos, su única diferencia se da en los atributos. A continuación se muestra una tabla con el API actual: Atributos Métodos Eventos error state load() loadstart error canPlayType(type) progress network state play() suspend src pause() abort currentSrc addTrack(label, kind, language) error networkState emptied preload stalled buffered play ready state pause readyState loadedmetadata seeking loadeddata controls waiting

controls playing volume canplay muted canplaythrough tracks seeking tracks seeked playback state timeupdate currentTime ended startTime ratechange muted paused defaultPlaybackRate playbackRate played seekable ended autoplay loop width [video only] height [video only] videoWidth [video only] videoHeight [video only] poster [video only] Gracias a JavaScript y a este nuevo API, tenemos el control completo sobre los elementos multimedia. Esto significa que podemos crearnos nuestros propios controles, extendiendo los que nos ofrece el navegador. Un simple ejemplo de acceso al API del elemento video: video.addEventlListener('canplay', function(e) ( this.volume = 0.4; anltscurrentia mes 1401 ais payo

+, false); 6.4 FULLSCREEN VIDEO Flash ha ofrecido un modo de pantalla completa durante muchos años a la que muchos navegadores se han resistido. La razón principal es la seguridad; ya que si se fuerza a una aplicación o web a funcionar a pantalla completa, el usuario pierde el control del propio navegador, la barra de tareas y controles estándar del sistema operativo. Puede que el usuario no sepa después volver del modo de pantalla completa, o puede haber problemas de seguridad relacionados, como la simulación del sistema operativo, petición de password, etc. Este nuevo API establece un único elemento full-screen. Está pensado para imágenes, video y juegos que utilizan el elemento canvas. Una vez que un elemento pasa a pantalla completa, aparece un mensaje de forma temporal para informar al usuario de que puede presionar la tecla esc en cualquier momento para volver a la ventana anterior. Las principales propiedad, métodos y estilos son: e element.requestFullScreen(): hace que un elemento individual pase a pantalla completa. document .getElementBylId ("myvideo") .requestFullScreen(). e document.cancelFullScreen (): sale del modo pantalla completa y vuelve a la vista del documento. e document.fullScreen: devuelve true si el navegador está en pantalla completa. e :full-screen: se trata de una pseudo-clase CSS que se aplica a un elemento cuando está en modo pantalla completa. Además, podemos modificar los estilos del elemento utilizando CSS: tmyelement [ wide 00px ) imyelement : full-screen [ width: 100$; ) fmyelement : full-screen img ( Wide 00

6.5 AUDIO El elemento multimedia audio es muy similar en cuanto a funcionalidad al elemento video. La principal diferencia existe al indicar el atributo contro1so no. Si lo especificamos, el elemento se mostrará en la página juntamente con los controles. Si no lo hacemos, el audio se reproducirá, pero no existirá ningún elemento visual en el documento. Por supuesto, el elemento existirá en el DOM y tendremos acceso completo a su API desde JavaScript. 6.5.1 MARCADO Para hacer funcionar el audio en HTML, al igual que con el video es suficiente con incluir lo siguiente: Los formatos soportados por los navegadores son los siguientes: MP3 MP4 WAV OGG Opera No No Si SÍ Firefox No No SÍ SÍ Chrome SÍ SÍ SÍ SÍ 1E9+ Si Si No No Safari Si Si Si No Por lo tanto, la mejor solución en estos momentos es ofrecer tanto el formato libre OGG, como el propietario MP3, marcado de la siguiente manera: Ejercicio 6 Ver enunciado ÍNDICE DE CONTENIDOS Multimedia 6.1 Vídeo

6.2 Codecs, la nueva guerra 6.3 API multimedia 6.4 Fullscreen video 6.5 Audio

— Anterior Siguiente => CAPÍTULO 7 CANVAS El elemento canvas proporciona un API para dibujar líneas, formas, imágenes, texto, etc en 2D, sobre el lienzo que del elemento. Este API ya está siento utilizado de manera exhaustiva, en la creación de fondos interactivos, elementos de navegación, herramientas de dibujado, juegos o emuladores. Éste elemento canvas es uno de los elementos que cuenta con una de las mayores especificaciones dentro de HTML5. De hecho, el API de dibujado en 2D se ha separado en un documento a parte. Un ejemplo de lo que se puede llegar a crear, es la recreación del programa MS Paint incluido en Windows 95. 600 CanvasPaint A Pi Mostrar un menú Figura 7.1 MS Paint desarrollado sobre canvas 7.1 ELEMENTOS BÁSICOS

Para comenzar a utilizar el elemento canvas, debemos colocarlo en el documento. El marcado es extremadamente sencillo: Éste nos recuerda mucho al elemento img, pero sin los atributos src y alt. En realidad, el elemento canvas solamente tiene los dos atributos mostrados en el ejemplo anterior: width Y height, ambos opcionales y que pueden establecerse mediante las propiedades DOM. Cuando estos dos atributos no se especifican, el lienzo (canvas) inicial será de 300px de ancho por 150px de alto. Este elemento, además y como muchos otros, pueden modificarse utilizando CSS. Podemos aplicar cualquier estilo, pero las reglas afectarán al elemento, no a lo dibujado en el lienzo. En la actualidad, todos los navegadores son compatibles con el elemento canvas, la diferencia entre ellos radica en qué funcionalidades del API han implementado. Ahora que el elemento canvas está definido en el documento, la manera de dibujar en él es a través de JavaScript. El primer paso es obtener el contexto de dibujado. crea una superficie de dibujo de tamaño fijo que expone uno o más contextos de representación, que se utilizan para crear y manipular el contenido mostrado. En el contexto de representación 2D, (existe otro contexto de representación en 3D, llamado WebGL), el canvas está inicialmente en blanco y, para mostrar algo, es necesario el acceso de un script al contexto de representación para que pueda dibujar en él. El método DOM getContext sirve para obtener el contexto de representación y sus funciones de dibujo. var canvas = document .getElementByld('tutorial'); var ctx = canvas.getContext ('2d'); El siguiente ejemplo dibujaría dos rectángulos que se cruzan, uno de los cuales tiene transparencia alfa. SOniptlype> apple arilon/ aves epi window.onload = function() ( var canvas = document .getFElementByld ("canvas"); if (canvas.getContext) ( Vat tctaE_e anvas ger context Zu rro sra ll sieyls = “eos (2010), 0,10) 5 rx a eS (10, 10, 00, D0)+5 esco dea LL sieyls = MreciEn O, DU, 200, Ue) A RSC SOS O O O 10)

y; Sci

Atento 600 Rectángulos semitransparentes e? Mostrar un menú Figura 7.2 Rectángulos semitransparentes en canvas 7.2 DIBUJAR FORMAS Para empezar a dibujar formas, es necesario hablar primero de la cuadrícula del canvas O espacio de coordenadas. Normalmente, una unidad en la cuadrícula corresponde a un px en el lienzo. El punto de origen de esta cuadrícula se coloca en la esquina superior izquierda (coordenadas(0,0)). Todos los elementos se colocan con relación a este origen. Desgraciadamente, canvas solamente admite una forma primitiva: los rectángulos, por lo que el resto de las formas deberán crearse mediante la combinación de una o más funciones. Existen tres funciones que dibujan un rectángulo en el lienzo: e fillRect (x, y, width, height): dibuja un rectángulo relleno e strokeRect (x, y, width, height): dibuja un contorno rectangular e clearRect (x, y width, height): borra el área especificada y hace que sea totalmente transparente. Cada una de estas funciones tiene los mismos parámetros. x e y especifican la posición en el lienzo. width es la anchura y height la altura. var Canvas = document .getElementByld ('tutorial'); var ctx = canvas.getContext ('2d'); dieses ral LL lisc. (29 29 OQ, 100) +

Suso lencia (de, 49 0, 50) + (EA SEO RS (00 20) 510) 7 La función fillrRect dibuja un gran cuadrado negro de 100x100 px. La función clearRect elimina un cuadrado de 60x60 px del centro y finalmente el strokeRect dibuja un contorno rectangular de 50x50 px en el interior del cuadrado despejado. A diferencia de las funciones de rutas que veremos en la siguiente sección, las tres funciones de rectángulo se dibujan inmediatamente en el lienzo. e e600 Dibujar rectángulos e Mostrar un menú Figura 7.3 Dibujado de rectángulos en canvas 7.3 RUTAS Gracias al API 2D, es posible movernos a través del canvas y dibujar líneas y formas. Las rutas son utilizadas para dibujar formas (líneas, curvas, polígonos, etc) que de otra forma no podríamos conseguir. El primer paso para crear una ruta es llamar al método beginPath. Internamente, las rutas se almacenan como una lista de subrutas (líneas, arcos, etc.) que, en conjunto, forman una figura. Cada vez que se llama a este método, la lista se pone a cero y podemos empezar a dibujar nuevas formas. El paso final sería llamar al método closePath: este método intenta cerrar la forma trazando una línea recta desde el punto actual hasta el inicial. Si la forma ya se ha cerrado o hay solo un punto en la lista, esta función no hace nada. var Canvas = document .getElementByld('tutorial'); var context = canvas.getContext ('2d'); context .beginPath (); //... path drawing operations context .closePath(); El siguiente paso es dibujar la forma como tal. Para ello, disponemos de algunas

funciones de dibujado de líneas y arcos, que especifican las rutas a dibujar. 7.3.1 MÉTODO LINETO Para dibujar líneas rectas utilizamos el método lineTo. Este método toma dos argumentos x e y, que son las coordenadas del punto final de la línea. El punto de partida depende de las rutas anteriores. En el siguiente ejemplo se dibujan dos triángulos, uno relleno y el otro únicamente trazado. En primer lugar se llama al método beginPath para iniciar una nueva ruta. A continuación, utilizamos el método moveTo para mover el punto de partida hasta la posición deseada. Finalmente se dibujan dos líneas que forman dos lados del triángulo. Al llamar al método closePath, éste traza una línea al origen, completando el triángulo. // Triángulo relleno ctx.beginPath(); ARMONIA) Sesto Las a (LOS, 20) $ exo Lao (27 0/5) Acro osea O) $ esoo eat LL (0) ¡TEN QUO AE razado ctx.beginPath(); CEXAMON STONES AS) Seo sas ta (125, 41) easy dato (dis 2031) SACOS eb caen (TAS IAS (E En ambos casos utilizamos dos funciones de pintado diferentes: stroke Y fi11. Stroke se utiliza para dibujar una forma con contorno, mientras que fi11 se utiliza para pintar una forma sólida. 7.3.2 ARCOS Para dibujar arcos o círculos se utiliza el método arc (la especificación también describe el método arcTo). Este método toma cinco parámetros: x e y, el radio, startAngle Y endAngle (que definen los puntos de inicio y final del arco en radianes) y anticlockwise (un valor booleano que, cuando tiene valor true dibuja el arco de modo levógiro y viceversa cuando es false). Un ejemplo algo más complejo que los anteriores utilizando el método arc sería: for (var 1=0;1<4;1++)( soja (ere JO? IES TADA

The text on this page is estimated to be only 74.24% accurate

cubpegin Bao var Xx = 20] 007 // coordenada x var y = Amis, // coordenada y var radius = 20; radio del arco var startAngle = 0; ¿ias amalcacul relel estrene var endAngle => Math (Mothers 1/2 p0// punto tunel var anticlockwise = 1%52==0 ? false : true; ctx.arc(x,y, radius, startAngle,endAngle, anticlockwise); e (asi) Stats deal (0) e j else ( CS IEO SA (0) e 600 Arcos pr UVUO ON 30) vwO00 Mostrar un menú Figura 7.4 Dibujado de arcos en canvas Nota Los métodos arc, bezier Y quadratic Utilizan radianes, pero si preferimos trabajar en grados, es necesario convertirlo a radianes. Esta el la operación que tenemos que llevar a cabo: var radians = degrees * Math.PI / 180; 7.3.3 MÉTODO MOVETO Disponemos de la función moveTo, que en realidad, aunque no dibuja nada, podemos imaginárnosla como 'si levantas un lápiz desde un punto a otro en un papel y lo colocas en el siguiente'. Esta función es utilizada para colocar el punto de partida en otro lugar o para dibujar rutas inconexas. clLx a bDegrnBat ni) EA EME (1D TO DO 0) Macia 2 LME)? Y Sxmcculo Esxeerlioje

The text on this page is estimated to be only 68.17% accurate

ce elosebpat ni) A (e us ral lisuyls = 'iuma"ctx.beginPath(); Ser sc (1 187 307 0), Maca, 21, tales) y // boca (dextrógiro) ctx.closePath(); (Sie o GEL) E ctx.moveTo (65,65); ctx.beginPath(); EEx. arc (60, 65,5, 0), Math. prx2- true), // oo izquierdo ctricos etat ni) Seco Meat LL (E EPXAMONE NO (IS OO): ctx.beginPath(); etx. arc (90, 65,5, 0, Math. p1x2, true), // oJo derecho cuellos en ati) esco eL LL 0) E e00 Cara sonriente :) 7 Mostrar un menú Figura 7.5 Dibujar una cara sonriente en canvas 7,4 COLORES Si queremos aplicar colores a una forma, hay dos características importantes que podemos utilizar: fil1Style Y strokeStyle. fillStyle = color strokeStyle = color strokeStyle se utiliza para configurar el color del contorno de la forma y fillstyle es para el color de relleno. Color puede ser una cadena que representa un valor de color CSS, un objeto degradado o un objeto modelo.

The text on this page is estimated to be only 65.50% accurate

// todos ellos configuran fillstyle a 'naranja (orange) ctx.fillStyle = "orange"; ctx.fillStyle = "fFFAS0O0"; Cies ea ll suyle = "recio (aan, 105970) Sesto a Ll Sieyls E Mesias a 0, di) E Ejemplo de filistyle: Einicio elcen) Al ora (bucla Op al os (wei T=0* 7I<6% TD) 4 Gusto ea Ste ls = “resi (Y 5 Merci alo (13034202 aL) 3 Y, 7 Merci loo (22 or) e Y 0) Elle (2) AAA) DS a) y Ejemplo de strokeStyle: ECON elbecnO) Al sor (ver i=0pi

var Canvas = document .getElementBylId ('tutorial'); WEE EAS var gradient = ctx.createl gradient.addCo] gradient.addCo] lsStyle = MRSEENOS CUR 23 3 canvas .getContext ('2d'); inearGradient (0, [SESTOR O) [ut TOO gradient; 0, 0, 0, canvas.width, canvas.height); canvas .height); El código anterior creamos un degradado lineal al que aplicamos dos pasos de color. Los argumentos de createlinearGradient son el punto de inicio del degradado (x1 e y1) y el punto final del degradado (x2 e y2). En este caso el degradado comienza en la esquina superior izquierda, y termina en la esquina inferior izquierda. Utilizamos este degradado para pintar el fondo de un rectángulo. e00 Gradiente lineal Mostrar un menú Figura 7.6 Degradado lineal Los degradados radiales son muy similares, con la excepción que definimos el radio después de cada coordenada: AZ ea, MZ, MEE var Canvas = document .getElementBylId ('tutorial'); var ctx = canvas.getContext ('2d'); gradient = ctx.createRadialGradient (canvas.widt canvas.heig 0, canvas .widt canvas.heig LSO) + gradient.addCo] gradient.addCo] lStyle = RESET (AL 413 45 ESE II [eso IO). gradient; 0, canvas.width, canvas.width);

La única diferencia es la manera en la que se ha creado el degradado. En este ejemplo, el primer punto del degradado se define en el centro del canvas, con radio cero. El siguiente punto se define con un radio de 150px pero su origen es el mismo, lo que produce un degradado circular. eS Gradiente radial e? Mostrar un menú Figura 7.7 Degradado radial Los patrones son incluso más sencillos de utilizar. Es necesaria una fuente (como una imagen, un canvas o un elemento de vídeo) y posteriormente utilizamos esta fuente en el método createPattern y el resultado de éste en el método fillstyle. La única consideración a tener en cuenta es que, al utilizar elementos de imagen o vídeo, éstos tienen que haber terminado de cargarse para poder utilizarlos. En el siguiente ejemplo, expandimos el canvas para que ocupe toda la ventana, y cuando se carga la imagen, la utilizamos como patrón de repetición. var Canvas = document .getElementByld ('tutorial'); var img = document .createElement ('img'); var ctx = canvas.getContext ('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; mg .onloadi= EuUnction () A ctx.fillStyle = ctx.createPattern(this, 'repeat'); cen REC OO canvas eden canvas neg) y; imag se avatar por,

600 Patrones e Mostrar un menú Figura 7.8 Uso de patrones en canvas 7.6 TRANSPARENCIAS Además de dibujar formas opacas en el lienzo, también podemos dibujar formas semitransparentes. Esto se hace mediante el establecimiento de la propiedad globalAlpha O podríamos asignar un color semitransparente al trazo y/o al estilo de relleno. globalAlpha = transparency value Esta propiedad aplica un valor de transparencia a todas las formas dibujadas en el lienzo y puede ser útil si deseas dibujar un montón de formas en el lienzo con una transparencia similar; ya que debido a que las propiedades strokeStyle y fillStyle aceptan valores de color CSS3, podemos utilizar la siguiente notación para asignarles un color transparente. baaa les (O) A PL ellos jere ojal aaa Sad "FEDO"; esco tall sat (10,10, 197 1D) E e Pa LL Sic E OE Aus a rec (o O TD TO) ies Ba Ll Sisa "FO9E"; LA o al ee 10, VEO, PD 1D) y cal ESO Surro al ee (19) 1D LD, LS) E

The text on this page is estimated to be only 74.46% accurate

Suez, clllseyle = “aia // establecer valor de transparencia ctx.globalAlpha = 0.2; // Dibujar círculos semitransparentes ) soc (wee i=0p

MES) ESTILO) E ) EEES SEO (> 7.7.3 MÉTODO scAnE El siguiente método de transformación es el escalado. Se utiliza para aumentar o disminuir las unidades del tamaño de nuestro marco. Este método puede usarse para dibujar formas ampliadas o reducidas. Etés o EEES (ER. YO) $ x e y definen el factor de escala en la dirección horizontal y vertical respectivamente. Los valores menores que 1.0 reducen el tamaño de la unidad y los valores mayores que 1.0 aumentan el tamaño de la unidad. Por defecto, una unidad en el área de trabajo equivale exactamente a un píxel. Si aplicamos, por ejemplo, un factor de escalado de 0.5, la unidad resultante será 0.5 píxeles, de manera que las formas se dibujarán a mitad de su tamaño. 7.8 ANIMACIONES Como estamos utilizando scripts para controlar los elementos canvas, resulta muy fácil hacer animaciones (interactivas). Sin embargo, el elemento canvas no fue diseñado para ser utilizado de esta manera (a diferencia de flash) por lo que existen limitaciones. Probablemente, la mayor limitación es que una vez que se dibuja una forma, se queda de esa manera. Si necesitamos moverla, tenemos que volver a dibujar dicha forma y todo lo que se dibujó anteriormente. Los pasos básicos a seguir son los siguientes: 1. Borrar el lienzo: a menos que las formas que se dibujen llenen el lienzo completo (por ejemplo, una imagen de fondo), se necesitará borrar cualquier forma que se haya dibujado con anterioridad. La forma más sencilla de hacerlo es utilizando el método clearrect. 2. Guardar el estado de canvas: si se va a modificar alguna configuración (estilos, transformaciones) que afectan al estado de canvas. E Dibujar formas animadas: representación del marco. Restaurar el estado de canvas: restaurar el estado antes de dibujar un nuevo marco. S 7.8.1 CONTROL

Las formas se dibujan en el lienzo mediante el uso de los métodos canvas directamente O llamando a funciones personalizadas. Necesitamos una manera de ejecutar nuestras funciones de dibujo en un período de tiempo. Hay dos formas de controlar una animación como ésta. En primer lugar está las funciones setIinterval Y setTimeout, que se pueden utilizar para llamar a una función específica durante un período determinado de tiempo. setInterval (animateShape, 500); setTimeout (animateshape, 500); El segundo método que podemos utilizar para controlar una animación es el input del usuario. Si quisiéramos hacer un juego, podríamos utilizar los eventos de teclado o de ratón para controlar la animación. Al establecer EventListeners, Capturamos cualquier interacción del usuario y ejecutamos nuestras funciones de animación. Ejercicio 7 Ver enunciado ÍNDICE DE CONTENIDOS Canvas 7.1 Elementos básicos 7.2 Dibujar formas 7.3 Rutas 7.4 Colores 7.5 Degradados y patrones 7.6 Transparencias 7.7 Transformaciones 7.8 Animaciones

— Anterior Siguiente => CAPÍTULO 8 ALMACENAMIENTO LOCAL El almacenamiento de datos es fundamental en cualquier aplicación web o de escritorio. Hasta ahora, el almacenamiento de datos en la web se realizaba en el servidor, y era necesario algún tipo de conexión con el cliente para trabajar con estos datos. Con HTML5 disponemos de tres tecnologías que permiten que las aplicaciones almacenen datos en los dispositivos cliente. Según las necesidades de la aplicación, la información puede sincronizarse también con el servidor o permanecer siempre en el cliente. Estas son las posibilidades que tenemos: e Web Storage: http://www.w3.org/TR/webstorage/. Es el sistema de almacenamiento más simple, ya que los datos se almacenan en parejas de clave/valor. Ampliamente soportado por todos los navegadores. e Web SQL Database: http: //www.w3.org/TR/webdatabase/. Sistema de almacenamiento basado en SQL. La especificación indica que no va a ser mantenido en el futuro, pero actualmente su uso está muy extendido y es soportado por Chrome, Safari y Opera. e IndexedDB: http://www.w3.org/TR/Indexeddb/. Sistema de almacenamiento basado en objetos. Actualmente soportado por Chrome, Firefox e Internet Explorer. 8.1 WEB STORAGE Este API de almacenamiento ofrece dos posibilidades para guardar datos en el navegador: sessionStorage Y localStorage. El primero mantiene los datos durante la sesión actual (mientras la ventana o pestaña se mantenga abierta), mientras que el segundo almacena los datos hasta que sean eliminados explícitamente por la aplicación o el usuario. Ambos modos de almacenamiento se encuentran relacionados con el dominio que los ha creado. e sessionStorage: objeto global que mantiene un área de almacenamiento disponible a lo largo de la duración de la sesión de la ventana o pestaña. La sesión persiste mientras que la ventana permanezca abierta y sobrevive a recargas de página. Si se abre una nueva página en una pestaña o ventana, una nueva sesión es inicializada, por lo que no es posible acceder a los datos de otra sesión. e localStorage: el almacenamiento local por su parte, funciona de la misma forma que el almacenamiento de sesión, con la excepción de que son capaces de almacenar los datos por dominio y persistir más allá de la sesión actual, aunque el navegador se cierre o el dispositivo se reinicie.

Nota ' Cuando hacemos referencia la ventana o pestaña, nos estamos refiriendo al objeto window. Una nueva ventana abierta utilizando el método window. open (), pertenece a la misma sesión. Tanto sessionStorage COMO localStorage forman parte del Web Storage, por lo que comparten el mismo AP! : readonly attribute unsigned long length; getter DOMString key(in unsigned long index); getter DOMString getltem(in DOMString key); setter creator void setltem(in DOMString key, in any data); deleter void removeltem(in DOMString key); volar (e Este API hace que sea muy sencillo acceder a los datos. El método setItem almacena el valor, y el método getItem lo obtiene, como se muestra a continuación: sessionStorage.setltem('twitter', 'fstarkyhach'); E / alert( sessionStorage.getltem('twitter') ); / muestra fstarkyhach Es importante darse cuenta, que tal y como se indica en el API, el método getItem siempre devuelve un String, por lo que si intentamos almacenar un objeto, el valor devuelto será "[Object object]". El mismo problema ocurre con los número, por lo que es importante tenerlo en cuenta para evitar posibles errores. Por ejemplo: sessionStorage.setltem('total', 120); function calcularCosteEnvio(envio) ( return sessionStorage.getltem('total') + envio; alert (calcularCosteEnvio(25)); En este caso, esperamos que el coste total (120) se almacene como número, y al añadir el coste del envío, el resultado sea 145. Pero como sessionStorage devuelve un String, el resultado no es el esperado sino 12025. 8.1.1 ELIMINANDO DATOS Disponemos de tres formas de eliminar datos del almacenamiento local: utilizando delete, removeltem Y clear. El método removeltem toma como parámetro el nombre de la clave a eliminar (el mismo que utilizamos en getItem Y setItem), para eliminar un ítem en particular. Por su parte, el método clear, elimina todas las entradas del objeto. sessionStorage.setltem('twitter', 'fstarkyhach');

sessionStorage.setltem('flickr', 'starky.hach'); alert ( sessionStorage.length ); sessionStorag .removeltem('twitter'); alert ( sessionStorage.length ); sessionStorage.clear(); alert( sessionStorage.length ); 8.1.2 ALMACENANDO ALGO MÁS QUE STRINGS Una manera de almacenar objetos es utilizando |]SON. Como la representación de los objetos en JSON puede realizarse a través de texto, podemos almacenar estas cadenas de texto y recuperarlas posteriormente para convertirlas en objetos. var videoDetalls = ( title MET author : ['Andy Wachowski"' "Larry Wachowski'], description "Wake up Neo, the Matrix has you...', etc age "320 y; sessionStorage.setltem('videoDetails', JSON.stringify(videoDetails) ); var videoDetails = JSON.parse(sessionStorage.getltem('videoDetails'); 8.1.3 EVENTOS DE ALMACENAMIENTO Una de las funcionalidades más interesantes de Web Storage es que incluye una serie de eventos que nos indican cuándo se ha producido un cambio en los datos almacenados. Estos eventos no se lanzan en la ventana actual donde se han producido los cambios, sino en el resto de ventadas donde los datos pueden verse afectados. Esto quiere decir que los eventos para sessionStorage son lanzados en los iframe dentro de la misma página, o en las ventanas abiertas con window. open (). Para localStorage, todas las ventanas abiertas con el mismo origen (protocolo + host + puerto) reciben los eventos. Cuando se lanzan los eventos, éstos contienen toda la información asociada con el cambio de datos: StorageEvent ( readonly readonly readonl readonl readon]l es LY LY LY DOMString key; any oldValue; any newValue; DOMStieitmgAurls Storage storageArea; storageArea hace referencia al objeto sessionStorage O localStorage. Estos eventos se

lanzan dentro del objeto window: function handleStorage (event) ( vent = event || window.event; // support IE8 if (event.newalue === null) ([ // 1t was removed // Do somthing + else ( // Do somthing else window.addEventListener('storage', handleStorage, false); window.attachEvent ('storage', handleStorage); Ejercicio 8 Ver enunciado 8.2 WEB SQL Web SQL es otra manera de almacenar y acceder a datos en el dispositivo. Realmente, no forma parte de la especificación de HTML5, pero es ampliamente utilizado para el desarrollo de aplicaciones web. Como su nombre indica, es una base de datos basada en SQL, más concretamente en SOlLite. La utilización del API se resume en tres simples métodos: e openDatabase: abrir (o crear y abrir) una base de datos en el navegador del cliente. e transaction: iniciar una transacción. e executeSgl: ejecutar una sentencia SQL. Como en la mayoría de librearías de JavaScript, el API de Web SQL realiza llamadas diferidas a funciones, una vez completadas las operaciones. transaction.executeSagl (sql, [], function () ( // my executed code lives here 105 Debido a la naturaleza de estas llamadas, significa que el API de Web SQL es asíncrono, por lo que es necesario tener cuidado con el orden en el que se ejecutan las sentencias SQL. Sin embargo, las sentencias SQL se encolan y son ejecutadas en orden, por lo que podemos estar tranquilos en ese sentido: podemos crear tablas y tener la seguridad que van a ser creadas antes de acceder a los datos. 8.2.1 CREANDO Y ABRIENDO LA BD El uso clásico de la API implica abrir (o crear) la base de datos y ejecutar algunas

sentencias SQL. Al abrir la base de datos por primera vez, ésta es creada automáticamente. Es necesario especificar el número de versión de base de datos con el que se desea trabajar, y si no especificamos correctamente éste número de versión, es posible que provoquemos un error del tipo INVALID_STATE_ERROR. Mati ani Ao penDatrabaseimycaa OM tas tea at aba Ser LAO ZONE La última versión de la especificación incluye un quinto argumento en la función openDatabase, pero no es soportado por muchos navegadores. Los valores que pasamos a esta función son los siguientes: 1. El nombre de la base de datos. 2. El número de versión de base de datos con el que deseamos trabajar. 3. Un texto descriptivo de la base de datos. 4. Tamaño estimado de la base de datos, en bytes. El valor de retorno de esta función es un objeto que dispone de un método transaction, a través del cual vamos a ejecutar las sentencias SQL. 8.2.2 TRANSACCIONES Ahora que tenemos la base de datos abierta, podemos crear transacciones para ejecutar nuestras sentencias SQL. La idea de utilizar transacciones, en lugar de ejecutar las sentencias directamente, es la posibilidad de realizar rollback. Esto quiere decir, que si la transacción falla por algún motivo, se vuelve al estado inicial, como si nada hubiese pasado. db transaction (function (Ex) tx.executeSgl('DROP TABLE foo'); // known to fail - so should rollback the DROP statement exe cut es ql AiN SERIAN TIO too (dE Sex) MAUI OOD ara) o): o Ebimeue oa (Sii) Al alert (err.message); H; Una vez listo el objeto transacción (tx en el ejemplo), podemos ejecutar sentencias SQL. 8.2.3 EJECUTAR SENTENCIAS SQL El método executesg1 es utilizado tanto para sentencias de escritura como de lectura. Incluye protección contra ataques de inyección SQL y proporciona llamadas a métodos (callback) para procesar los resultados devueltos por una consulta SQL. Su sintaxis es la siguiente:

cio). Eicemaciat oa ce iacic ao (ese) Al tx.executeSgl (sqglStatement, arguments, callback, errorCallback); DE Donde: 1. sglStatement: indica la sentencia SQL a ejecutar. Como hemos dicho, puede ser cualquier tipo de sentencia; creación de tabla, insertar un registro, realizar una consulta, etc. 2. arguments: Corresponde con un array de argumentos que pasamos a la sentencia SQL. Es recomendable pasar los argumentos a la sentencia de esta manera, ya que el propio método se ocupa de prevenir inyecciones SQL. 3. callback: función a ejecutar cuando la transacción se ha realizado de manera correcta. Toma como parámetros la propia transacción y el resultado de la transacción. 4. erroCallback: función a ejecutar cuando la transacción se ha producido un error en la sentencia SQL. Toma como parámetros la propia transacción y el error producido. Un ejemplo de selección de registros sería el siguiente: abmearan's acetona ero (E) tx.executeSgl ('SELECT * FROM foo WHERE id = ?', [5], cuncrlos cal local (es. cestiltesy) var len = results.rows.length, 1; so (1. = 0 L < lens dle) Y altent (results onows. item(s) text) h, iuncrclo. Srrorte local (es, Sto) 1 alert (error.message); ) ) 10 La función de callback recibe como argumentos la transacción (de nuevo) y un objeto que contiene los resultados. Este objeto contiene una propiedad rows, donde rows.item(i) contiene la representación de la fila concreta. Si nuestra tabla contiene un campo que se llama nombre, podemos acceder a dicho campo de la siguiente manera: results.rows.item(i).nombre 8.2.4 CREAR TABLAS

La primera tarea a realizar cuando trabajamos con una base de datos es crear las tablas necesarias para almacenar los datos. Como hemos comentado antes, este proceso se realiza a través de una sentencia SQL, dentro de una transacción. Vamos a crear una base de datos para almacenar tweets que posteriormente obtendremos de internet: db = openDatabase('tweetdb', '1.0', 'All my tweets', 2 * 1024 * 1024); lo EicEm Scrims) Al tx.executeSgl('CREATE TABLE IF NOT EXISTS tweets (id, , getTweets); y) user, date, text)", 8.2.5 INSERTAR DATOS Una vez creada la tabla, el siguiente paso es insertar los datos correspondientes. Vamos a suponer que hemos realizado una petición AJAX a la API de Twitter, que nos ha devuelto una serie de tweets que queremos almacenar en nuestra base de datos. La función getTweets tendría este aspecto: function getTweets() ( Were uueses = Sears (loss)? S.each(tweets, funection(tweet) ( aberrantes Icon (Sa (a) var time = (new Date(Date.parse (tweet.created_at))).getTime (); tx.executeSgl (' INSERT INTO tweets (id, user, date, text) VALUES (7, En E e [tweet.id, tweet.from_user, time / 1000, tweet.text]) 7 10 0 ) | Nota Insertando cada tweet en una nueva transacción, nos aseguramos que si se produce un error en alguna de ellas (ya existía el tweet), se van a seguir ejecutando el resto transacciones. 8.2.6 OBTENER DATOS Finalmente, una vez que los datos se encuentran almacenados en la base de datos, sólo nos queda consultarlos. Como siempre, ejecutamos las sentencia SQL dentro de una transacción y proveemos la función que procesará los datos obtenidos: db transaction (Function (Ex) A tx.executesSgl ('SELECT * FROM tweets WHERE date > ?7', Funcion (fe, cssultes) [time], var html = [], len = results.rows.length;

A A OA menda ¡usd (UL e ES SÚIL ES: 05 cena (a) cues + “E/ o tweetEl.innerHTML = html.join(''); Ejercicio 9 Ver enunciado 8.3 INDEXEDDB IndexedDB no es una base de datos relacional, sino que se podría llamar un almacén de objetos ya que en la base de datos que creemos, existen almacenes y en su interior añadimos objetos (como el siguiente): aL0 ls AL SISlA y nombre: "Memoria RAM" En IndexedDB, al igual que en Web SQL, al abrir una base de datos debemos indicar su nombre y la versión concreta. Posteriormente debemos crear los almacenes de objetos, que es muy parecido a un archivador con índices, que nos permite encontrar de una manera muy rápida el objeto que buscamos. Una vez el almacén está listo, podemos almacenar cualquier tipo de objeto con el índice que definamos. No importa el tipo de objeto que almacenemos, ni tienen que tener las mismas propiedades. 8.3.1 CREANDO Y ABRIENDO LA BD De forma similar a como hacíamos en Web SQL, vamos a abrir una base de datos, y trabajar directamente con el objeto que nos devuelve. De nuevo, al igual que en Web SQL, las peticiones a la base de datos se realizan de manera asíncrona. window.indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozInde xedDB; if ('webkitIndexedDB" in window) ( window. IDBTransaction = window.webkitIDBTransaction; window. IDBKeyRange = window.webkitIDBKeyRange; var request = indexedDB.open('videos'); request.onerror = function () ( console.log('failed to open indexedDB');

1 request.onsuccess = function (event) ( - OMC O Mano! // handle version ys Ahora que la base de datos esta abierta (y asumiendo que no hay errores), se ejecutará el evento onsuccess. Antes de poder crear almacenes de objetos, tenemos que tener en cuenta los siguiente: e Necesitamos un manejador para poder realizar transacciones de inserción y obtención de datos. e Hay que especificar la versión de la base de datos. Si no existe una versión definida, significa que la base de datos no está aún creada. El método onsuccess recibe como parámetro un evento, al igual que lo hace cualquier otro método escuchador de eventos. Dentro de este objeto, encontramos una propiedad llamada target, y dentro de ésta otra propiedad llamada result, que contiene el resultado de la operación. En este caso específico, event .target.result contiene la base de datos que acabamos de abrir. var db = null; var request = indexedDB.open('videos'); request.onsuccess = function (event) ( LOA MEE = SiHOme 1 request.onerror = function alert ('Something failed: (event) ( '" + event.target.message); y; Es importante indicar que en IndexedDB, los errores que se producen escalan hasta el objeto request. Esto quiere decir, que si un error ocurre en cualquier petición (por ejemplo una consulta de datos), en este caso mostraría una alerta con el error. 8.3.2 CONTROL DE VERSIONES El primer paso tras abrir la base de datos es realizar un control de versiones de la base de datos. Podemos utilizar cualquier cadena de caracteres como identificador de la versión, pero lo lógico es seguir un patrón típico de software, como '0.1', '0.2', etc. Al abrir la base de datos, debemos comprobar si la versión actual de la base de datos coincide con la última versión de la aplicación. Si son diferentes, tendremos que realizar la actualización.

Variado ama ers ton O request.onsuccess = function (event) ( // cache a copy of the database handle for the future db = event.target.result; // handle version control 1f (version != db.version) ( // set the version to 0.1 var verReguest = db.setVersion (version); verRequest.onsuccess = function (event) ( // now we're ready to create the object store! H; verRequest.onerror = function () ( alert ('unable to set the version :' + version); y; ) y; 8.3.3 CREAR ALMACENES DE OBJETOS Tanto la primera vez que creamos nuestra base de datos, como a la hora de actualizarla, debemos crear los almacenes de objetos correspondientes. var verRequest = db.setVersion (version); verRequest.onsuccess = function (event) ( var store = db.createObjectStore('blockbusters', ( keyPath: 'title', autolncrement: false t this point we would notify our code // that the object SOLES un Q o, 2 ye Para este ejemplo, hemos creado un único almacén de objetos, pero lo normal es disponer de varios y que puedan relacionarse entre ellos. El método create0bjectStore admite dos parámetros: e name: indica el nombre del almacén de objetos. e optionalParameters: este parámetro permite definir cual va a ser el índice de los objetos, a través del cual se van a realizar las búsquedas y que por tanto debe ser único. Si no deseamos que este índice se incremente automáticamente al añadir nuevos objetos, también lo podemos indicar aquí. Al añadir un nuevo objeto, es importante asegurarnos que disponga de la propiedad definida como índice, y que

su valor sea único. Es posible que deseemos añadir nuevos índices a nuestros objetos, con el fin de poder realizar búsquedas posteriormente. Podemos realizarlo de la siguiente manera: store.createlndex('director', 'director', [ unique: false )); Hemos añadido un nuevo índice al almacén, llamado director (primer argumento), y hemos indicado que el nombre de la propiedad del objeto es director (segundo argumento), a través del cual vamos a realizar las búsquedas. Evidentemente, varias películas pueden tener el mismo director, por lo que este valor no puede ser único. De esta manera, podemos almacenar objetos de este tipo: title: "Belly Dance Bruce -— Final Strike", date: (new Date) .getTime(), // released TODAY! director: "Bruce Awesome", length: 169, // in minutes Bari g Or cover: "/images/wobble. jpg" 8.3.4 AÑADIR OBJETOS AL ALMACÉN Disponemos de dos métodos para añadir objetos al almacén: add y put. e add: añade un nuevo objeto al almacén. Es obligatorio que los nuevos datos no existan en el almacén, de otro modo esto provocaría un error de tipo Constr alme rnom. e put: en cambio, éste método actualiza el valor del objeto si existe, o lo añade si no existe en el almacén. var video = ( title: "Belly Dance Bruce -— Final Strike", date: (new Date) .getTime(), // released TODAY! director: "Bruce Awesome", length: 169, // in minutes iseucaliao¡s ALO), cover: "/images/wobble.j3Jpg" 1 var myIDBTransaction = window. IDBTransaction || window.webkitIDBTransaction || £ READ WRITE: 'readwrite' );

var transaction = db.transaction(['blockbusters'], myIDBTransaction.READ_WRITE); var store = transaction.objectStore('blockbusters'); // var request store.add (video); var request = store.put (video); Analizemos las tres últimas líneas, utilizadas para añadir un nuevo objeto al almacén: 1. transaction = db.transaction(['blockbusters'], READ_WRITE) : Creamos una nueva transacción de lectura/escritura, sobre los almacenes indicados (en este caso sólo 'blockbusters'), pero podrían ser varios si es necesario. Si no necesitamos que la transacción sea de escritura, podemos indicarlo con la propiedad DBTransaction.READ_ONLY.. 2. store = transaction.objectStore('blockbusters')! obtenemos el almacén de objetos sobre el que queremos realizar las operaciones, que debe ser uno de los indicados en la transacción. Con la referencia a este objeto, podemos ejecutar las operaciones de add, put, get, delete, etc. 3. request = store.put (video) : insertamos el objeto en el almacén. Si la transacción se ha realizado correctamente, se llamará al evento onsuccess, mientras que si ha ocurrido un error, se llamará a onerror. 8.3.5 OBTENER OBJETOS DEL ALMACÉN El proceso para acceder a los objetos almacenados es muy similar a lo realizado para insertarlos. Seguimos necesitando una transacción, pero en este caso de sólo lectura. El proceso es el siguiente: var myIDBTransaction = window. IDBTransaction || window.webkitIDBTransaction MIRE ADE var key = "Belly Dance Bruce - Final Strike"; var transaction = db.transaction(['blockbusters'], myIDBTransaction.READ); var store = transaction.objectStore('blockbusters'); // var request = store.add (video); var request = store.get (key); En este caso, lo importante es que la clave (la variable key) que hemos pasado al método get, buscará el valor que contiene en la propiedad que hemos definido como keyPath al crear el almacén de objetos. | o Nota ** |

El método get produce el mismo resultado tanto si el objeto existe en el almacén como si no, pero con un valor undefined. Para evitar esta situación, es recomendable utilizar el método opencursor () con la misma clave. Si el objeto no existe, el valor del resultado es null. Para obtener todos los objetos de un almacén, en lugar de un único objeto, debemos hacer uso del método openCursor. Este método acepta como parámetro un objeto de tipo |DBKeyRange, que podemos utilizar para acotar la búsqueda. var transaction = db.transaction(['blockbusters'], myIDBTransaction.READ); var store = transaction.objectStore('blockbusters'); var data = []; var request = store.openCursor lÍ(); request.onsuccess = function (event) ( var cursor = event.target.result; IN US O) | // value is the stored obje data.push(cursor.value); // get the next object cursor. continue (); + else ( y En ese ejemplo, abrimos el almacén de objetos al igual que lo hemos venido haciendo, pero en lugar de obtener un único objeto con el método get, abrimos un cursor. Esto nos permite iterar por los objetos devueltos por el cursor, todos como es este caso, o los que cumplan una condición concreta. El objeto en concreto al que apunta el cursor en la iteración actual se encuentra almacenado en su propiedad cursor.value. Avanzar en el cursor, para obtener el siguiente objeto, es tan sencillo como llamar al método continue () del cursor, lo que provocará una nueva llamada al evento onsuccess, siendo nosotros los que tenemos que controlar si el cursor ya no apunta a ningún objeto (MES). 8.3.6 ELIMINAR OBJETOS DEL ALMACÉN La última operación a realizar sobre el almacén de objetos, es eliminar datos existentes. De nuevo, el proceso es prácticamente el mismo que para obtener datos: var myIDBTransaction = window. IDBTransaction

|| window.webkitIDBTransaction || f READ_ WRITE: 'readwrite' ); var transaction = db.transaction(['blockbusters'], myIDBTransaction.READ_WRITE); var store = transaction.objectStore('blockbusters'); véis EeQUest = Sor celsrs (Uuey) 7 Si queremos eliminar todos los objetos de un almacén, podemos utilizar el método clear (), siguiente el mismo proceso visto anteriormente. var request = store.clear(); Ejercicio 10 Ver enunciado ÍNDICE DE CONTENIDOS Almacenamiento local 8.1 Web Storage 8.2 Web SQL 8.3 IndexedDB

— Anterior Siguiente => CAPÍTULO 9 SIN CONEXIÓN Si bien todos los navegadores tienen mecanismos de almacenamiento en caché, estos sistemas no son fiables y no siempre funcionan como debieran. HTML5 permite resolver algunas de las molestias asociadas al trabajo sin conexión mediante la interfaz ApplicationCache. Algunas de las ventajas que conlleva el uso de ésta caché para una aplicación son: e Navegación sin conexión: los usuarios pueden explorar todo el sitio web sin conexión. e Velocidad: los recursos almacenados en caché son locales y, por tanto, se cargan más rápido. e Reducción de carga del servidor: el navegador solo descarga recursos del servidor que han cambiado. Para poder trabajar sin conexión, una aplicación únicamente necesita de un archivo de manifiesto, el cual indica al navegador que ficheros debe almacenar en la caché local. El contenido del manifiesto puede ser tan simple como un listado de archivos. Una vez que el navegador ha descargado y almacenado los ficheros (html, CSS, imágenes, javascripts, etc), el navegador hace uso de estos ficheros, incluso cuando el usuario actualiza la página en su navegador. Además de especificar qué ficheros van a ser almacenados en la caché, es posible indicar cuáles no tienen que serlo, y por tanto obligar al navegador a realizar una petición de dichos ficheros al servidor. Finalmente, si intentamos acceder a un fichero no almacenado en local, y no disponemos de conexión, podemos mostrar un recurso que previamente hemos almacenado en la caché. 9.1 EL ARCHIVO DE MANIFIESTO DE CACHÉ El archivo de manifiesto es lo que le indica al navegador cuando y qué tiene que almacenar en su caché, y qué tiene que traerse de la Web. Indicar al navegador el manifiesto que tiene que utilizar es muy sencillo: IDO Si Bes

El atributo manifest debe estar incluido en todas las páginas de nuestra aplicación, que queramos que se almacenen en la caché. Es decir, además de los ficheros indicados en el manifiesto, la propia página que incluye el manifiesto es almacenada en la caché. El navegador no almacenará en caché ninguna página que no contenga el atributo manifest (a menos que esa página aparezca explícitamente en el propio archivo de manifiesto). El atributo manifest puede señalar a una URL absoluta o a una ruta relativa, pero las URL absolutas deben tener el mismo origen que la aplicación web. Un archivo de manifiesto puede tener cualquier extensión, pero se debe mostrar con el tipo MIME correcto: El tipo MIME con el que se deben mostrar los archivos de manifiesto es text/cachemanifest. Es posible que se tenga que añadir un tipo de archivo personalizado a la configuración de .htaccess o de tu servidor web. 9.1.1 ESTRUCTURA Ejemplo de un archivo de manifiesto sencillo: CACHE MANIFEST index.html stylesheet.css images/logo.png scripts/main.jJs El archivo de manifiesto del ejemplo permite almacenar en caché los cuatro archivos especificados. El formato del manifiesto es importante: e La cadena CACHE MANIFEST debe aparecer en la primera línea y es obligatoria. e Dentro del manifiesto, los ficheros son listados dentro de categorías, también conocidos como namespaces. Si no se especifica ninguna categoría, todos los ficheros pertenecen a la categoría CACHE. Un ejemplo más complejo sería: CACHE MANIFEST 5 ALO SUS CACHE RENA. OO index.html

stylesheet.css images/logo.png scripts/main.jJs + Resources that require the user to be online. NETWORK: login.php /myapi http://api.twitter.com + static.html will be served if main.py is inaccessible + offline.Jpg will be served in place of all images in images/large/ + offline.html will be served in place of all other .html files FAL] BACK: /mail M7 Y Siecicao el images/large/ images/offline.jpg in toleran! Un archivo de manifiesto puede incluir tres categorías: CACHE, NETWORK Y FALLBACK. e CACHE: esta es la sección predeterminada para las entradas. Los archivos incluidos en esta sección (o inmediatamente después de CACHE MANIFEST) se almacenarán en caché explícitamente después de descargarse por primera vez. e NETWORK: los archivos incluidos en esta sección son recursos permitidos que requieren conexión al servidor. En todas las solicitudes enviadas a estos recursos se omite la caché, incluso si el usuario está trabajando sin conexión. Se pueden utilizar caracteres comodín. e FALLBACK: se trata de una sección opcional en la que se especifican páginas CACH si Ea alternativas en caso de no poder acceder a un recurso. La primera ur1 corresponde al recurso y la segunda, a la página alternativa. Ambas uri deben estar relacionadas y tener el mismo origen que el archivo de manifiesto. Se pueden utilizar caracteres comodín. E MANIFEST MO O ESAS $ Explicitly cached entries index.html css/style.css + offline.html will be displayed if the user is offline FALL BACK: PY) Sas ein + Al l other resources require the user to be online.

NETWORK : + Additional resources to cache CACHÉ: images/logol.png images/logo2.png images/logo3.png Nota Las peticiones de recursos que den como resultado un error 404 (por ejemplo una imagen no encontrada), mostrarán en este caso el fichero offl1ine.html 9.2 CÓMO SERVIR EL MANIFIESTO Como hemos comentado anteriormente, el manifiesto puede tener cualquier extensión (aunque se recomienda que sea .appcache), pero lo importante es que el servidor envíe el fichero con el tipo MIME correcto. Si utilizamos Apache, es tan sencillo como añadir la siguiente línea al fichero mime .types: text/cache-manifest appcache Esta configuración dependerá del servidor web que utilicemos. De todas maneras, para asegurarnos que el servidor está enviando el manifiesto con la cabecera correcta, podemos utilizar una herramienta como cur1 de la siguiente manera: curl -1 http://mysite.com/manifest.appcache O bien a través de las herramientas de desarrollo integradas en Google Chrome, Safari y Firefox. De cualquiera de las maneras, la respuesta tendría que ser algo parecido a esto: ¿a OOO DEtesMon SS Sa OO ASIS 0 G ME Servera ame 22 Se (UA) MO ES S 1/2 ES O SMS STO OSUID AN PE ASEO Last-Modified: Tue, 31 Aug 2010 03:11:00 GMI Accept-Ranges: bytes Content-Length: 113 Content-Type: text/cache-manifest 9.3 PROCESO DE CACHEADO Cuando visitamos una página que hace uso de la cache de aplicación, el proceso de cacheado que se sigue es el siguiente:

Navegador: solicita la página http: //html5app.com/ Servidor: devuelve index.html Navegador: procesa la página index.html y solicita los recursos asociados, como imágenes, javascripts, hojas de estilos y el manifiesto. Servidor: devuelve todos los recursos solicitados. Navegador: procesa el manifiesto y solicita, de nuevo, todos los recursos definidos en el manifiesto. Efectivamente, se produce una doble petición. Servidor: devuelve todos los recursos del manifiesto solicitados. Navegador: la cache de aplicación está actualizada, y se lanzan los eventos asociados. Ahora, el navegador está listo y la caché contiene los ficheros indicados en el manifiesto. Si el manifiesto no ha cambiado, y la página se recarga, ocurre lo siguiente: L: Ze Navegador: vuelve a solicitar la página http: //html5app.com/ Navegador: detecta que tiene una copia local de index.html y la sirve de manera local. Navegador: procesa la página index.html y los recursos existentes en la caché se sirven de manera local. Navegador: solicita de nuevo el manifiesto al servidor. Servidor: devuelve un código 304 indicando que no ha cambiado nada en el manifiesto. Una vez que el navegador tiene almacenados los recursos en su caché, los sirve de manera local y después solicita el manifiesto. Como se puede ver en la siguiente captura de pantalla, Google Chrome únicamente solicita al servidor aquellos ficheros que no se encuentran en la caché de la aplicación.

e006 / [5% Your clock and mine x W S € 3 C |) ww.arkaitzgarro.com The time on your computer is 22:17:12 and the time on the server is 10:30:10 Elements Resources | Network | Sources Timeline Profiles Audits Console Name Status Size Time Path 2 Text yaa Content Latency maltes 60 ms 91 ms =| time/ 200 2ms f h y Jexamples/chO7 EN oK nds dia e 1 ms o al time.css E 200 AE a he) 4ms ==) /examples/ch07/time oK dias dias 2 ms o A ind mm licatio... (f A a = HS rom cache ==) /examples/ch07/time oK LINES 3 ms So _— server-time.js er 304 PRO | 234B 80ms A =J /examples/ch07/time Not Modified aio pios 318 80 ms » ¡B, =|¡Q|¡s=|¡O SN) All | Documents Stylesheets Images Scripts XHR Fonts WebSockets Other o Figura 9.1 Peticiones realizadas por Google Chrome Si deseamos actualizar alguno de los recursos de la aplicación, tendremos que actualizar primero el manifiesto, para obligar al navegador a solicitar de nuevo todos los recursos. Para ello, es necesario marcar de alguna manera que el manifiesto ha cambiado, aunque los ficheros a cachear sean los mismos. Una práctica muy sencilla es añadir una número de versión o la fecha de modificación del manifiesto: ZOO DO ISS Una vez que el manifiesto ha cambiado, el comportamiento del navegador es el siguiente: 1. Navegador: vuelve a solicitar la página http: //html5app.com/ 2. Navegador: detecta que tiene una copia local de index.html y la sirve de manera local. 3. Navegador: procesa la página index.html y los recursos existentes en la caché se sirven de manera local. 4. Navegador: solicita de nuevo el manifiesto al servidor. 5. Servidor: devuelve el nuevo manifiesto modificado. 6. Navegador: procesa el manifiesto y solicita todos los recursos definidos en el manifiesto. 7. Servidor: devuelve todos los recursos del manifiesto solicitados.

8. Navegador: la cache de aplicación está actualizada, y se lanzan los eventos asociados. Hay que destacar, que a pesar de haber modificado los recursos en el navegador, estos cambios no se producen en este momento, ya que se siguen utilizando los cargados previamente. La nueva caché solo estaría disponible si volviésemos a recargar la página. Una manera de modificar este comportamiento es accediendo al objeto applicationCache. 9.4 ACTUALIZACIÓN DE LA MEMORIA CACHÉ El objeto window. applicationCache permite acceder mediante JavaScript a la caché de aplicación del navegador. Su propiedad status permite comprobar el estado de la memoria caché, y es el encargado de notificarnos que se ha producido un cambio en la caché local. var applache = window.applicationCache; switch (appCache.status) ( case appCache.UNCACHED: // UNCACHED == 0 return 'UNCACHED'; break; case applache.IDLE: // IDLE == 1 Return DER. orealke, Case appCache.CHECKING: // CHECKING == 2 return 'CHECKING'; break; Case appCache.DOWNLOADING: // DOWNLOADING == 3 return 'DOWNLOADING'; break; case appCache.UPDATEREADY: —// UPDATEREADY == 4 return 'UPDATEREADY'; break; case appCache.OBSOLETE: // OBSOLETE == 5 return 'OBSOLETE'; break; der atte: return 'UKNOWN CACHE STATUS'; break; y; Para actualizar la caché mediante JavaScript, primero se debe hacer una llamada a applicationCache.update () . Al hacer esa llamada, se intentará actualizar la caché del usuario (para lo cual será necesario que haya cambiado el archivo de manifiesto). Finalmente, cuando el estado de applicationCache.status Sea UPDATEREADY, al llamar a applicationCache.swapCache (), se sustituirá la antigua caché por la nueva. var applache = window.applicationCache; appCache.update(); // Attempt to update the user's cache. if (appCache.status == window.applicationCache.UPDATEREADY) ( appCache.swapCache (); // The fetch was successful, swap in the new cache.

Al utilizar update () Y swapCache () de este modo, no se muestran los recursos actualizados a los usuarios. El flujo indicado solo sirve para pedirle al navegador que busque un nuevo archivo de manifiesto, que descargue el contenido actualizado que se especifica y que actualice la caché de la aplicación. Por tanto, la página se tiene que volver a cargar dos veces para que se muestre el nuevo contenido a los usuarios: una vez para extraer una nueva caché de aplicación y otra para actualizar el contenido de la página. Para que los usuarios puedan acceder a la versión más reciente del contenido de tu sitio, podemos establecer un escuchador que controle el evento updateready cuando se cargue la página: window.addEventListener ('load', function(e) ( window.applicationCache.addEventListener ('updateready', function(e) ( if (window.applicationCache.status == window.applicationCache.UPDATEREA DNA) A // Browser downloaded a new app cache. // Swap it in and reload the page to get the new hotness. window.applicationCache.swapCache (); (contain (Ane w ver siontolt enlis site stavamilable Load tE) window.location.reload/(); ) + else ( // Manifest didn't changed. Nothing new to server. , ¡EEES SNE: ES S)A Hay, además, algunos eventos adicionales que permiten controlar el estado de la caché. El navegador activa eventos para una serie de acciones (como el progreso de las descargas, la actualización de la caché de las aplicaciones y los estados de error). El siguiente fragmento permite establecer escuchadores de eventos para cada tipo de evento de caché: function handleCacheEvent (e) () function handleCacheError (e) ( alert ('Error: Cache failed to update!'); y; // Fired after the first cache of the manifest. appCache.addEventlistener ('cached', handleCacheEvent, false); // Checking for an update. Always the first event fired in the sequence.

appCache.addEventlistener ('checking', handleCacheEvent, false); // An update was found. The browser is fetching resources. appCache.addEventlListener ('downloading', handleCacheEvent, false); // The manifest returns 404 or 410, the download failed, // or the manifest changed while the download was in progress. appCache.addEventlistener('error', handleCacheError, false , // Efired after the first download of the manifest. appCache.addEventlistener ('noupdate', handleCacheEvent, false); // Fired 16 the manifest file returas a 404 or 410. // This results in the application cache being deleted. appCache.addEventlistener ('obsolete', handleCacheEvent, false); // Fired for each resource listed in the manifest as it is being fetched. appCache.addEventlistener ('progress', handleCacheEvent, false); // Fired when the manifest resources have been newly redownloaded. appCache.addEventlistener ('updateready', handleCacheEvent, false); Si no se puede descargar el archivo de manifiesto o algún recurso especificado en él, fallará todo el proceso de actualización. Si se produce ese fallo, el navegador seguirá utilizando la antigua caché de la aplicación. 9.5 EVENTOS ONLINE/OFFLINE Como parte de la especificación de HTML5, el objeto navigator incluye una propiedad que nos indica si se dispone de conexión o no, concretamente navigator.onLine. Sin embargo, esta propiedad no se comporta de manera correcta en la mayoría de navegadores, y únicamente cambia su estado al indicar de manera explícita que funcione en modo offline. Como desarrolladores, lo que realmente nos interesa es conocer si realmente hay conexión o no con el servidor. Una manera de identificar si existe conexión a internet, es utilizar la categoría FALLBACK del manifiesto. En esta categoría podemos indicar dos ficheros JavaScript que detectan si estamos online o no: CACHE MANIFEST FALLBACK: online.js offline.js online.js contiene:

setOnline (true); Y offline.js contiene: setOnline (false); En nuestra aplicación, creamos una función llamada testonline que dinámicamente crea un elemento

— Anterior Siguiente => CAPÍTULO 10 DRAG AND DROP Durante años, hemos utilizado bibliotecas como ¡Query y Dojo para conseguir funcionalidades complejas en las interfaces de usuario como las animaciones, las esquinas redondeadas y la función de arrastrar y soltar. Esta última funcionalidad (Drag and Drop, DnD) tiene una gran importancia en HTML5, y de hecho se ha integrado en el API. En la especificación, este API se define como un mecanismo basado en eventos, donde identificamos los elementos que deseamos arrastrar con el atributo draggable y desde JavaScript escuchamos los eventos que se producen, para proporcionar la funcionalidad deseada. Por defecto, todos los enlaces, imágenes y nodos de texto (o selecciones de texto) de un documento HTML son arrastables, pero no hay ningún evento asociado a estas acciones, por lo que poco más podemos hacer, a excepción de la funcionalidad que nos ofrezca el navegador o el propio sistema operativo (guardar las imágenes en el escritorio, crear ficheros de texto, etc). 10.1 DETECCIÓN DE LA FUNCIONALIDAD Aunque la compatibilidad actual de los navegadores con esta API es bastante amplia, hay que tener en cuenta que los dispositivos móviles no soportan esta funcionalidad. Si nuestro sitio web está siendo accedido desde un dispositivo móvil, y tenemos implementada esta funcionalidad (por ejemplo en una cesta de la compra), debemos proveer otra solución para que nuestro sitio web se comporte de manera correcta, y no perjudicar la experiencia del usuario. La manera mas sencilla de comprobar la disponibilidad de este API, es utilizar la biblioteca Modernizr, la cual nos indica si el navegador soporta esta funcionalidad: if (Modernizr.draganddrop) ( // Browser supports HIML5 DnD. + else ( ES) Rsullosials 0 E llos ANS ALE TAO NOIA CES ED 10.2 CREACIÓN DE CONTENIDO ARRASTRABLE Hacer que un elemento se pueda arrastrar es muy sencillo. Solo hay que establecer el atributo draggable="true" en el elemento que se quiere mover. La función de arrastre se puede habilitar prácticamente en cualquier elemento, incluidos archivos, imágenes,

enlaces, listas u otros nodos DOM.

A

B

C

Una ayuda visual al usuario, para indicar que un elemento es arrastable, es transformar el aspecto tanto del elemento como del cursor. Con CSS esto es muy sencillo: [draggable] ( user-select: none; .Ccolumn:hover ( border: 2px dotted $666666; background-color: +tccc; order aa m0 box-shadow: inset 0 0 3px *+000; CUESOr; move, 10.3 EVENTOS DE ARRASTRE La especificación define hasta siete eventos que son lanzados tanto por los elementos de origen (los que son arrastrados) com para los elementos de destino (donde soltamos el elemento arrastrado). Son los siguientes: e dragstart: comienza el arrastrado. El target del evento hace referencia al elemento que está siendo arrastrado. e drag: el elemento se ha movido. El target del evento hace referencia al elemento que está siendo arrastrado. Este evento se dispara tantas veces como se mueva el elemento. e dragenter: se dispara cuando un elemento que está siendo arrastrado entra en un contenedor. El target del evento hace referencia al elemento contenedor. e dragleave: el elemento arrastrado ha salido del contenedor. El target del evento hace referencia al elemento contenedor. e dragover: el elemento se ha movido dentro del contenedor. El target del evento hace referencia al elemento contenedor. Como el comportamiento por defecto es denegar el árop, la función debe retornar el valor false o llamar al método preventDefault del evento para que indicar que se puede el soltar elemento. e drop: el elemento arrastrado has sido exitosamente soltado en el elemento

contenedor. El target del evento hace referencia al elemento contenedor. e dragend: se ha dejado de arrastrar el elemento, con éxito o no. El target del evento hace referencia al elemento arrastrado. Para organizar el flujo de DnD, necesitamos un elemento de origen (en el que se origina el movimiento de arrastre), la carga de datos (la información que va asociada al elemento arrastrado) y un elemento de destino (el área en la que se soltarán los datos). El elemento de origen puede ser una imagen, una lista, un enlace, un objeto de archivo, un bloque de HTML o cualquier otro elemento, al igual que la zona de destino. 10.3.1 COMIENZO DE LA OPERACIÓN DE ARRASTRE Una vez que se haya definido el atributo draggable="true" en los elementos que queremos convertir en arrastables, debemos añadir los escuchadores necesarios para reaccionar antes los eventos que se lanzan desde los elementos. El primer evento de los que define la especificación se produce cuando un elemento comienza a ser arrastrado. Un ejemplo muy sencillo en el que cambiamos la transparencia de un elemento al comenzar a ser arrastrado: function handleDragStart (e) ( this.style.opacity = '0.4'; var cols = document .querySelectorAll1 ('tcolumns .column'); Dl cstorairacia. eau (egiks,. Eume (iaa) A col .addEventlListener ('dragstart', handleDragStart, false); yd 7 No debemos olvidarnos de volver a fijar la transparencia del elemento en el 100% una vez completada la operación de arrastre, ya que de otro modo, seguiría siendo transparente una vez finalizado la operación de arrastre. 10.3.2 DRAGENTER, DRAGOVER Y DRAGLEAVE Los controladores de eventos dragenter, dragover Y dragleave se pueden utilizar para proporcionar pistas visuales adicionales durante el proceso de arrastre. Por ejemplo, el borde de un elemento de destino se puede convertir en una línea discontinua al realizar una operación de arrastre. De esa forma, los usuarios podrán distinguir cuáles son los elementos de destino donde pueden soltar lo que están arrastrando. .column.over ( border: 2px dashed +000; function handleDragStart (e) ( taiststylesopaciey 04 se

function handleDragOver (e) ( 1f (e.preventDefault) ( .preventDefault (); // Necessary. Allows us to drop. ) e.dataTransfer.dropEffect = 'move'; return false; function handleDragEnter (e) ( // this / e.target is the current hover target. this.classList.add('over'); function handleDraglLeave (e) ( this.classList.remove('over'); // this / e.target is previous target eleme var cols = document .querySelectorAll ('tcolumns .column'); Dl. romracia. call tcals, Euncrelmon (coa) col .addEventListener ('dragstart', handleDragStart, false); col.addEventlListener ('dragenter', handleDragEnter, false); col.addEventlListener ('dragover', handleDragOver, false); col.addEventlListener ('dragleave', handleDragleave, false); Algunas consideraciones en el código anterior. Cuando algo es soltado sobre un elemento, se dispara el evento dragover, y tenemos la posibilidad de leer el objeto event .dataTransfer. Este objeto contiene los datos asociados a las operaciones de arrastre, como veremos más adelante. Tal y como hemos comentado anteriormente, cuando soltamos un elemento, hay que impedir el comportamiento predeterminado del navegador, que es denegar el drop. 10.3.3 FINALIZACIÓN DE LA OPERACIÓN DE ARRASTRE Para que se procese la operación de soltar, se debe añadir un escuchador para los eventos drop y dragend. En este controlador, habrá que impedir el comportamiento predeterminado del navegador para este tipo de operaciones, que puede ser abrir un enlace o mostrar una imagen. Para ello, evitamos la propagación del evento con e.stopPropagation/(). En nuestro ejemplo utilizaremos dragend para eliminar la clase over de cada columna: function handleDrop (e) (

// this / e.target is current target element. 1f (e.stopPropagation) ( e.stopPropagation(); // stops the browser from redirecting. ) // See the section on the DataTransfer object. e return false; function handleDragEnd (e) ( ¡l0 // this/e.target is the source node. Ol. tormiracia, call (cols, FEumcelomn (sal) col.classList.remove('over'); var cols = document .querySelectorAl1l ('tcolumns .column'); lo rtoriaacia. call (ess, Euimeeicon (esi) Al col .addEventListener '"dragstart', handleDragStart, false); col .addEventlListener ('dragenter', handleDragEnter, false); col .addEventListener ('dragover', handleDragOver, false); col.addEventlListener ('drop', handleDrop, false); ( ( ( col.addEventlListener ('dragleave', handleDragleave, false); ( ( col .addEventListener 'dragend', handleDragEnd, false); De 10.3.4 EL OBJETO DATATRANSFER La propiedad dataTransfer es el centro de desarrollo de toda la actividad de la función DnD, ya que contiene los datos que se envían en la acción de arrastre. La propiedad dataTransfer se establece en el evento dragstart y se lee/procesa en el evento drop. Al activar e.dataTransfer.setData (format, data), se establece el contenido del objeto en el tipo MIME y se transmite la carga de datos en forma de argumentos. En nuestro ejemplo, la carga de datos se ha establecido en el propio HTML del elemento de origen: vere Checo sicció. = GaulliLs function handleDragStart (e) ( this.style.opacity = '0.4'; my) dragSrcEl = this; F e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/html', this.innerHTML); dataTransfer también tiene el formato getData necesario para la extracción de los datos de arrastre por tipo de MIME. A continuación se indica la modificación necesaria para el procesamiento de la acción de arrastre de un elemento:

function handleDrop(e) ( // this/e.target is current target element. 1f (e.stopPropagation) ( e.stopPropagation(); // Stops some browsers from redirecting. ) // Don't do anything if dropping the same column we're dragging. 1f (dragSrcEl != this) ( // Set the source column's HTML to the HTML of the columnwe dropped on dragSrcEl.innerHTML = this.innerHTML; this.innerHTML = e.dataTransfer.getData('text/html'); ) Seu else; ) Hemos añadido una variable global llamada dragSrcEl para facilitar el cambio de posición de la columna. En handleDragStart (), la propiedad innerHTML de la columna de origen se almacena en esa variable y, posteriormente, se lee en handleDrop () para cambiar el HTML de las columnas de origen y destino. 10.4 ARRASTRE DE ARCHIVOS Las API de DnD permiten arrastrar archivos del escritorio a una aplicación web en la ventana del navegador. Para arrastrar un archivo desde el escritorio, se deben utilizar los eventos de DnD del mismo modo que otros tipos de contenido. La diferencia principal se encuentra en el controlador drop. En lugar de utilizar dataTransfer.getData() para acceder a los archivos, sus datos se encuentran en la propiedad dataTransfer.files: function handleDrop(e) ( e.stopPropagation(); // Stops some browsers from redirecting. .preventDefault (); var files = e.dataTransfer.files; so (mee 1 => 0, e se = dales] sr) Al // Read the File objects in this Filelist. Ejercicio 12 Ver enunciado ÍNDICE DE CONTENIDOS

Drag and Drop 10.1 Detección de la funcionalidad 10.2 Creación de contenido arrastrable 10.3 Eventos de arrastre 10.4 Arrastre de archivos

— Anterior Siguiente => CAPÍTULO 11 GEOLOCALIZACIÓN El uso del API de geolocalización es extremadamente sencillo. Soportado por todos los navegadores modernos, nos permite conocer la posición del usuario con mayor o menor precisión, según el método de localización utilizado. En la actualidad, disponemos de tres tecnologías para geolocalizar un usuario: e Vía |1P: todo dispositivo que se encuentra conectado a la red, tiene asignada una dirección |1P (Internet Protocol) pública que actúa, de forma muy simplificada, como un código postal. Evidentemente, esta no es la mejor manera de localización, pero sí nos da una ligera idea de dónde se encuentra. e Redes GSM: cualquier dispositivo que se conecte a una red telefonía, es capaz de obtener una posición aproximada basándose en una triangulación con las antenas de telefonía. Es un método sensiblemente más preciso que mediante la dirección IP, pero mucho menos que mediante GPS. e GPS: Global Positioning System o Sistema de Posicionamiento Global. Es el método más preciso, pudiendo concretar la posición del usuario con un margen de error de escasos metros. El primer paso es comprobar es la disponibilidad del API de geolocalización de HTML 5 en el explorador del usuario: 1f (Modernizr.geolocation) ( alert ('El explorador soporta geolocalización'); + else ( alert ('El explorador NO soporta geolocalización'); El API ofrece los siguientes métodos para geolocalizar la posición del usuario: e getCurrentPosition: obtiene la posición actual del usuario, utilizando la mejor tecnología posible. e watchPosition: consulta cada cierto tiempo la posición del usuario, ejecutando la función de callback indicada únicamente si la posición ha cambiado desde la última consulta. Ambos métodos se ejecutan de manera asíncrona para obtener la posición del usuario. Si es la primera vez que se solicita la localización al navegador, éste mostrará un mensaje pidiendo permiso al usuario para compartir su localización. Si el usuario no da su

permiso, el API llama a la función de error que hayamos definido. La especificación dice: "El navegador no debe enviar información sobre la localización a sitios sin el permiso explícito del usuario." Así pues, queda en manos de los navegadores informar al usuario que estamos intentando acceder a su posición actual. La forma de realizarlo depende del navegador. Por norma general, los navegadores de escritorio muestran un aviso no bloqueante, lo que permite seguir utilizando y ejecutando la aplicación. AS 9.9 7 5 ceotocation - Dive Into 1 x A o e» Qe. diveintohtml5.info/geolocation.html y ES O diveintohtml5.info quiere utilizar la ubicación de tu ordenador. Más información Xx A Figura 11.1 Petición para compartir localización en Chrome En cambio, en navegadores de dispositivos móviles, como Safari y Chrome, se muestra una ventana modal que bloquea la ejecución del código hasta que el usuario acepte o deniegue la solicitud de geolocalización. “http://diveintohtmi5.info” “http: //diveintohtmi5.info” desea utilizar su ubicación desea utilizar su ubicación actual | actual No permitir No permitir Figura 11.2 Petición para compartir localización en Safari Mobile y Chrome Mobile 11.1 MÉTODOS DEL API

El API de geolocalización del objeto navigator contiene tres métodos: e getCurrentPosition e watchPosition e clearWatch Los métodos watchPosition Y clearWatch están emparejados, de la misma manera que lo están setinterval y clearTimeout. watchPosition devuelve un identificador único, que permite cancelar posteriormente las consultas de posición pasando es identificador como parámetro a clearWatch. Tanto getCurrentPosition COMO watchPosition, son métodos muy parecidos, y toman los mismos parámetros: una función de éxito, una función de error y opciones de geolocalización. Un simple ejemplo de uso del API geolocalización es el siguiente: navigator.geolocation.getCurrentPosition(function (position) ( alert ('We found you!'); // now do something with the position data y 11.1.1 FUNCIÓN DE ÉXITO Si el usuario permite que el navegador comparta la localización, y no se produce ningún otro error, se llama a la función de éxito, que es el primer argumento de las funciones de getCurrentPosition Y watchPosition. Ésta función recibe como parámetro un objeto position que contiene dos propiedades: un objeto coords (contiene las coordenadas) una marca de tiempo timestamp. El objeto de coordenadas es el que nos interesa, ya que es el que contiene la información sobre la geolocalización. Sus propiedades son las siguientes: e readonly attribute double latitude e readonly attribute double longitude e readonly attribute double accuracy La propiedad accuracy contiene la precisión de las coordenadas en metros. Podemos utilizarlo para mostrar un radio de precisión de la posición en nuestro mapa. Aunque es complicado de confirmar, es posible que esta información de geolocalización provenga de servicios propios de los fabricantes. Por ejemplo, Google dispone de una gran base de datos, que combinado con la información de la petición (como el hardware, la dirección |P, etc.) puede dar una localización. Esta información simplemente representa la posición del usuario, y no contiene nada más que nos pueda indicar la velocidad o dirección del usuario.

Utilizando la información de posición, es muy sencillo mostrar la posición del usuario en un mapa: if (navigator.geolocation) ( navigator.geolocation.getCurrentPosition(function (position) ( var coords = position.coords; showMap (coords.latitude, coords.longitude, coords.accuracy); ; Existe otro tipo de datos dentro del objeto coords, para dispositivos que dispongan de GPS, aunque la gran mayoría de navegadores establecerán estas propiedades como DLL IEA e readonly attribute double altitude e readonly attribute double altitudeAccuracy e readonly attribute double heading e readonly attribute double speed 11.1.2 OBTENIENDO DATOS EXTRA Actualmente, muchos de los dispositivos integran un GPS. Dependiendo del navegador o del sistema operativo, la información provista con la geolocalización puede incluir mucha más información que simplemente las coordenadas de la posición, como la velocidad y la altitud. En la mayoría de los casos, hay que especificar al API que utilice una mayor precisión para activar el GPS. Como siempre, hay que tener cuidado al utilizar el GPS, ya que consume muchísima batería y hay que utilizar esta tecnología únicamente si es estrictamente necesario. Para calcular la velocidad, el dispositivo necesita conocer la diferencia media entre las últimas localizaciones. Por esta razón, es necesario utilizar el método watchPosition y calcular la velocidad de la siguiente manera: var speedEl = document .getElementByld ('speed'); navigator.geolocation.watchPosition(function (geodata) ( var speed = geodata.coords.speed; 1f (speed === null || speed === 0) ( speedEl.innerHTML = "You're standing still!"; + else ( // speed is in metres per second speedEl.innerHTML = speed + “Mps”; ) A INCA (0)

pesca obama aótlo = "Wiclole o ePsceormlne sosa == », [ enableHighAccuracy: true ) YE 11.1.3 FUNCIÓN DE ERROR El segundo parámetro para los métodos getCurrentPosition Y watchPosition €s la función de error. Esta función es importante si queremos proveer de un segundo método alternativo para introducir la localización, por ejemplo de manera manual, o queremos informar al usuario del error. Esta función se ejecuta cuando el usuario deniega la petición de localización, o cuando estamos consultando la posición pero el dispositivo pierde la recepción de la localización. La función de error recibe un único argumento con dos propiedades: e readonly attribute unsigned short code e readonly attribute DOMString message El código de error puede contener los siguientes valores: e PERMISSION_DENIED (valor = 1) e POSITION_UNAVAILABLE (valor = 2) e TIMEOUT (valor = 3) 11.1.4 CONFIGURAR LA GEOLOCALIZACIÓN Finalmente, el tercer argumento para los métodos getCurrentPosition Y watchPosition contiene las opciones de geolocalización. Todas estas configuraciones son opcionales, puede que no se tengan en cuenta por los navegadores. e enableHighAccuracy: booleano, por defecto false e timeout: en milisegundos, por defecto infinito e maximumAge: en milisegundos, por defecto O Por ejemplo, para solicitar una alta precisión, Un timeout de dos segundos y no cachear las peticiones, llamamos al método getCurrentPosition con las siguientes opciones: navigator.geolocation.getCurrentPosition(success, error, ( enableHighAccuracy: true timeout: 2000 maximumAge: 0 y Ejercicio 13

Ver enunciado ÍNDICE DE CONTENIDOS Geolocalización 11.1 Métodos del API

— Anterior Siguiente => CAPÍTULO 12 WEB WORKERS Los navegadores ejecutan las aplicaciones en un único thread, lo que significa que si JavaScript está ejecutando una tarea muy complicada, que se traduce en tiempo de procesado, el rendimiento del navegador se ve afectado. Los Web workers se introdujeron con la idea de simplificar la ejecución de threads en el navegador. Un worker permite crear un entorno en el que un bloque de código JavaScript puede ejecutarse de manera paralela sin afectar al thread principal del navegador. Los Web workers utilizan un protocolo de paso de mensajes similar a los utilizados en programación paralela. Estos Web workers se ejecutan en un subproceso aislado. Como resultado, es necesario que el código que ejecutan se encuentre en un archivo independiente. Sin embargo, antes de hacer esto, lo primero que se tiene que hacer es crear un nuevo objeto Worker en la página principal: var worker = new Worker ('task.3s'); Si el archivo especificado existe, el navegador generará un nuevo subproceso de Worker que descargará el archivo JavaScript de forma asíncrona. El Worker no comenzará a ejecutarse hasta que el archivo se haya descargado completamente. Si la ruta al nuevo Worker devuelve Un error 404, el Worker fallará automáticamente. Antes de comenzar a utilizar los Worker, es necesario conocer el protocolo de paso de mensajes, que también es utilizado en otras APIs como WebSocket y Server-Sent Event. 12.1 TRANSFERENCIA DE MENSAJES El API de transferencia de mensajes es una manera muy simple de enviar cadenas de caracteres entre un origen (o un dominio) a un destino. Por ejemplo podemos utilizarlo para enviar información a una ventana abierta como popup, o a un iframe dentro de la página, aún cuando tiene como origen otro dominio. La comunicación entre un Worker y su página principal se realiza mediante un modelo de evento y el método postMessage () . En función del navegador o de la versión, postMessage () puede aceptar una cadena o un objeto son como argumento único. Las últimas versiones de los navegadores modernos son compatibles con la transferencia de objetos Json. De todas maneras, siempre podemos utilizar los métodos JSON.stringify y JSON.parse para la transferencia de objetos entre el thread principal y los Worker.

A continuación, se muestra un ejemplo sobre cómo utilizar una cadena para transferir "Hello World" a un Worker en dowWork.3s. El Worker simplemente devuelve el mensaje que se le transfiere. Secuencia de comandos principal: worker .postMessage ('Hello World'); // Send data to our worker. doWork.3s (el Worker): self .addEventlistener ('message', function(e) ( self .postMessage(e.data); raise): Cuando se ejecuta postMessage () desde la página principal, el Worker es capaz de obtener este mensaje escuchando al evento message. Se puede acceder a los datos del mensaje (en este caso "Hello World") a través de la propiedad data del evento. Aunque este ejemplo concreto no es demasiado complejo, demuestra que postMessage () también sirve para transferir datos de vuelta al thread principal, una vez que los datos de origen se hayan procesado correctamente. Los mensajes que se transfieren entre el origen y los Worker se copian, no se pasan por referencia. Por ejemplo, en el siguiente ejemplo, a la propiedad msg del mensaje JSON se accede en las dos ubicaciones. Parece que el objeto se transfiere directamente al Worker aunque se esté ejecutando en un espacio específico e independiente. En realidad, lo que ocurre es que el objeto se serializa al transferirlo al Worker y, posteriormente, se anula la serialización en la otra fase del proceso. El origen y el Worker no comparten la misma instancia, por lo que el resultado final es la creación de un duplicado en cada transferencia. La mayoría de los navegadores implementan esta función mediante la codificación/descodificación son automática del valor en la otra fase del proceso, cuando el paso de objetos está soportado. En el siguiente ejemplo, que es más complejo, se transfieren mensajes utilizando objetos JavaScript. Secuencia de comandos principal: Say HI Send unknown command Stop worker EuincizLoa Say (O) A

The text on this page is estimated to be only 72.07% accurate

won ler aposiMes's age aiendi stan So ) Fueron stop worker .postMessage(('cmd': 'stop', 'msg': 'Bye')); ) function unknownCmd () ( WOB ESTADOS e Mess age ena E OO Nana IS Je ) Var worker = new Worker ('doWork.3s'); worker .addEventListener('message', function(e) ( document .getElementByld('result').textContent = e.data; bf EEES) $ (SERSE> doWork.js: this.addEventListener('message', function(e) var data = e.data; switch (data.cmd) ( case 'start': this.postMessage ('WORKER STARTED: break; Ccaseñistopie: this.postMessage ('WORKER STOPPED: nger work)'); 4 eE alMiSej) A datar msg e this closed, // Terminates the worker. break; default: this.postMessage ('Unknown command: yb +, false); '+data.msg); 12.2 UTILIZACIÓN DE WEB WORKERS Un Worker es una manera ejecutar código JavaScript de manera paralela al proceso principal, sin interferir con el navegador. El navegador sigue siendo responsable de solicitar y analizar ficheros, renderizar la vista, ejecutar JavaScript y cualquier otro proceso que consuma tiempo de procesado y que haga que el resto de tareas tengan que esperar. Y es aquí donde los Web workers toman importancia. (Cuttons milano tio

Al igual que con el resto de funcionalidades de HTML5, debemos comprobar su disponibilidad en el navegador en el que ejecutamos la aplicación: if(Modernizr.webworkers) ( alert('El explorador soporta Web workers'); + else ( alert('El explorador NO soporta Web workers'); Crear nuevo Worker es muy sencillo. Tan sólo tenemos que crear una nueva instancia del objeto worker, indicando como parámetro del constructor el fichero JavaScript que contiene el código que debe ejecutar el Worker. var worker = new Worker ('my_worker.>3s'); De esta manera tenemos disponible y listo para utilizar un nuevo Worker. En este momento, podríamos pensar que podemos llamar a métodos o utilizar objetos definidos dentro del nuevo Worker, pero no nada más lejos de la realidad. La única manera de comunicarnos con el nuevo Worker es a través del paso de mensajes, como hemos visto anteriormente. worker .postMessage ('Hello World'); Éste método únicamente acepta un parámetro, la cadena de texto a enviar al Worker. Por otra parte, la manera de recibir mensajes originados en el Worker es definiendo un escuchador para el evento message. Los datos incluidos por el Worker se encuentran disponibles en la propiedad data del evento. worker .addEventListener ('message', function(e) ( alert (e.data); op Talse) $ 12.2.1 DENTRO DE UN WORKER Evidentemente, dentro de un Worker necesitamos comunicarnos con el thread principal, tanto para recibir los datos de los mensajes como para nuevos datos de vuelta. Para ello, añadimos un escuchador para el evento message, y enviamos los datos de vuelta utilizando el mismo método postMessage. this.addEventListener('message', function(e) ( postMessage("I'm done!"); DA Es conveniente saber, que a diferencia de la ejecución un script en el documento principal, la visibilidad de un Worker es mucho más reducida. En concreto, la palabra

reservada this no hace referencia al objeto window, sino al Worker en sí mismo. Debido al comportamiento de ejecución en paralelo de los Web workers, éstos solo pueden acceder al siguiente conjunto de funciones de JavaScript (según la especificación): e Enviar datos Con postMessage y aceptar mensajes entrantes a través del evento onmessage. e close, para terminar con el Worker actual. e Realizar peticiones Ajax. e Utilizar las funciones de tiempo setTimeout () /clearTimeout () y setInterval ()/clearInterval (). e Las siguientes funciones de JavaScript: eval, isNaN, escape, etc. e WebSockets. e EventSource. e Bases de datos Web SOL, IndexedDB. e Web Workers. En cambio, los Workers NO pueden acceder a las siguientes funciones: e DOM (no es seguro para el subproceso). e Objeto window. e Objeto document. e Objeto parent. 12.3 SUBWORKERS Los Workers tienen la capacidad de generar Workers secundarios. Esto significa, que podemos dividir la tarea principal en subtareas, y crear nuevos Workers dentro del Worker principal. Sin embargo, a la hora de utilizar los Subworkers, y antes de poder devolver el resultado final al hilo principal, es necesario asegurarse que todos los procesos han terminado. var pendingWorkers = 0, results = (),; onmessage = function (event) ( var data = JSON.parse(event.data), worker = null; pendingWorkers = data.length; tor (var 1 = 07 1 < data. lengta; 1++) [ worker = new Worker ('subworker.Js'); worker.postMessage (JSON.stringify(data[i])); worker.onmessage = storeResult;

function storeResult (event) ( var result = JSON.parse(event.data); pendingWorkers--; if (pendingWorkers <= 0) ( postMessage (JSON.stringify(results)); 12.4 GESTIONAR ERRORES Si se produce un error mientras se ejecuta un Worker, se activa un evento error. La interfaz incluye tres propiedades útiles para descubrir la causa del error: filename (el nombre de la secuencia de comandos del Worker que causó el error), lineno (el número de línea donde se produjo el error) y message (una descripción significativa del error). Ejemplo: workerWithError.js intenta ejecutar 1/x, donde el valor de x no se ha definido: ISSN ECONO ¡Omer (1) document .getElementByld('error') .textContent = [ "ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.messagel .join('') function onMsg(e) ( document .getElementByld('result').textContent = e.data; var worker = new Worker ('workerWithError.Js'); worker .addEventlistener ('message', onMsg, false); worker .addEventlListener ('error', onError, false); worker .postMessage(); // Start worker without a message.

workerWithError.js: self .addEventlistener ('message', function(e) ( postMessage (1/x); // Intentional error. y; 12.5 SEGURIDAD Debido a las restricciones de seguridad de Google Chrome (otros navegadores no aplican esta restricción), los Workers no se ejecutarán de forma local (por ejemplo, desde file://) en las últimas versiones del navegador. En su lugar, fallan de forma automática. Para ejecutar tu aplicación desde el esquema file://, ejecuta Chrome con el conjunto de marcadores --allow-file-access-from-files. Las secuencias de comandos del Worker deben ser archivos externos con el mismo esquema que su página de llamada. Por ello, no se puede cargar una secuencia de comandos desde una URL data: o una URL javascript:. Asimismo, una página https: no puede iniciar secuencias de comandos de Worker que comiencen con una URL http: . Ejercicio 14 Ver enunciado ÍNDICE DE CONTENIDOS Web workers 12.1 Transferencia de mensajes 12.2 Utilización de Web Workers 12.3 Subworkers 12.4 Gestionar errores 12.5 Seguridad

— Anterior Siguiente => CAPÍTULO 13 WEBSOCKETS 13.1 INTRODUCCIÓN Internet se ha creado en gran parte a partir del llamado paradigma solicitud/respuesta de HTTP. Un cliente carga una página web, se cierra la conexión y no ocurre nada hasta que el usuario hace clic en un enlace o envía un formulario. Hace ya algún tiempo que existen tecnologías que permiten al servidor enviar datos al cliente en el mismo momento que detecta que hay nuevos datos disponibles. Se conocen como "Push" o "Comet". Uno de los trucos más comunes para crear la ilusión de una conexión iniciada por el servidor se denomina Long Polling. Con el Long Polling, el cliente abre una conexión HTTP con el servidor, el cual la mantiene abierta hasta que se envíe una respuesta. Cada vez que el servidor tenga datos nuevos, enviará la respuesta. El Long Polling y otras técnicas funcionan bastante bien y de hecho ha sido utilizadas en muchas aplicaciones como el chat de Gmail. Los WebSockets nos ofrecen una conexión bidireccional entre el servidor y el navegador. Esta conexión se produce en tiempo real y se mantiene permanentemente abierta hasta que se cierre de manera explícita. Esto significa que cuando el servidor quiere enviar datos al servidor, el mensaje se traslada inmediatamente. Efectivamente, esto es lo que sucedía al utilizar tecnologías como Comet, pero se conseguía utilizando una serie de trucos. Si esto no funcionada, siempre era posible utilizar Ajax para conseguir un resultado parecido, pero sobrecargando el servidor de manera innecesaria. Si disponemos de un socket abierto, el servidor puede enviar datos a todos los clientes conectados a ese socket, sin tener que estar constantemente procesando peticiones de Ajax. La ventaja en cuanto a rendimiento y escalabilidad es bastante evidente al utilizar WebSockets. La latencia en las comunicaciones es otro de los beneficios de utilizar WebSockets. Como el socket está siempre abierto y escuchando, los datos son enviados inmediatamente desde el servidor al navegador, reduciendo el tiempo al mínimo, en comparación con un paradigma basado en Ajax, donde hay que realizar una petición, procesar la respuesta y enviarla de nuevo de vuelta. Finalmente, los datos a transmitir se reducen también de manera drástica, pasando de un mínimo de 200-300 bytes en peticiones Ajax, a 10-20 bytes utilizando websockets. 13.2 CREAR UN WEBSOCKET

El API de WebSocket es realmente sencillo de utilizar. Actualmente, los navegadores únicamente soportan el envío de cadenas de caracteres, y se realiza de una manera muy similar a la que utilizábamos para enviar mensajes en los Web Workers. El API está limitado a métodos para abrir la conexión, enviar y recibir datos y cerrar la conexión. Para abrir una conexión WebSocket, sólo tenemos que ejecutar el constructor WebSocket, que toma como parámetro la URL del socket a abrir. Hay que tener en cuenta que el protocolo a utilizar es ws: //: var socket = new WebSocket ('ws: //html5rocks.websocket .org/tweets'); También existe un protocolo wss:// para conexiones WebSocket seguras, de la misma forma que se utiliza https: // para las conexiones HTTP seguras. La URL que utilizamos para conectarnos con el WebSocket no tiene por qué pertenecer al mismo dominio que nuestro documento, por lo que podemos conectarnos a servicios de terceros sin problemas, expandiendo las posibilidades de nuestra aplicación. 13.3 COMUNICACIÓN CON EL SERVIDOR Cuando se establece una conexión con el servidor (cuando el evento open se activa), se puede empezar a enviar datos al servidor con el método sena a través del socket creado. tf seña new E MEN een socket .send("Hey there, I'm using WebSockets"); De la misma forma, el servidor puede enviarnos mensajes en cualquier momento. Cada vez que esto ocurra, se activa el evento onmessage. Los datos enviados por el servidor se encuentran en la propiedad data del objeto event. socket .onmessage = function (event) ( var data = JSON.parse(event.data); 1f (data.action == 'joined') ( aioslical Ll isccinae (1) + else ( showNewMessage (data.who, data.text); Dr El API incorpora además dos eventos que se disparan cuando el socket se abre y está listo, y cuando éste se va a cerrar: socket .onopen = function(e)í log("Welcome -— status "+this.readyState); ); socket .onclose = function(e)í log("Disconnected -— status "+this.readyState); );

13.4 WEBSOCKET EN EL SERVIDOR Al utilizar los WebSocket, se crea un patrón de uso completamente nuevo para las aplicaciones de servidor. Aunque las pilas de servidor tradicionales como Lamp están diseñadas a partir del ciclo de solicitud-respuesta de HTTP, a menudo dan problemas si hay muchas conexiones WebSocket abiertas. Mantener un gran número de conexiones abiertas de forma simultánea requiere una arquitectura capaz de recibir un alto nivel de concurrencia sin consumir muchos recursos. Estas arquitecturas suelen estar basadas en subprocesos o sistemas de z/s asíncronos. En el próximo capítulo sobre Server-Sent Events, veremos una implementación de un servidor web basado en JavaScript, llamado Node.js. Ejercicio 15 Ver enunciado ÍNDICE DE CONTENIDOS WebSockets 13.1 Introducción 13.2 Crear un WebSocket 13.3 Comunicación con el servidor 13.4 WebSocket en el servidor

— Anterior Siguiente => CAPÍTULO 14 EVENTSOURCE Los EventSource (también conocidos como Server-Sent Events), son eventos en tiempo real transmitidos por el servidor y recibidos en el navegador. Son similares a los WebSockets en que suceden el tiempo real, pero son principalmente un método de comunicación unidireccional desde el servidor. Al igual que en los WebSocket, creamos una nueva conexión indicando la URL, y el navegador intentará conectarse inmediatamente. El objeto EventSource dispone de los siguientes eventos: e open: se dispara cuando la conexión se ha establecido. e message: evento que indica la llegada de un mensaje nuevo. e error: se dispara cuando algo ha ido mal. Lo que hace a EventSource diferente es la manera en que controla las pérdidas de conexión y la gestión de los mensajes. Si la conexión se pierde por alguna razón, el API automáticamente trata de volver a conectarse. Además, al restablecer la conexión, el cliente envía al servidor la 1D del último mensaje que recibió. Esto permite al servidor, enviar al cliente todos los mensajes que no ha podido recibir. No es necesario realizar ninguna configuración especial en nuestro código, simplemente el servidor nos enviará los mensajes que no hemos recibido. Un sencillo ejemplo: var es = new EventSource('/bidding'); es.onopen = function () ( initialiseDatal(); yr s.onmessage = function (event) ( var data = JSON.parse(event.data); updateData (data.time, data.bid); y; 14,1 EVENTSOURCE EN EL SERVIDOR En el lado del servidor podemos seguir utilizando una solución basada en PHP y la pila completa LAMP, pero como Apache no se comporta de manera estable con conexiones

persistentes, constantemente trata de cerrar las conexiones y EventSource trata de volver a conectarse automáticamente. Esto da como resultado un comportamiento más parecido a Ajax que a una comunicación unidireccional y en tiempo real desde el servidor. Realmente, esta no es la mejor manera de aprovechar las ventajas de EventSource. Para ello, necesitamos una conexión persistente con el servidor, y LAMP no nos lo puede proporcionar. Actualmente existen soluciones de servidor basadas en eventos, como pueden ser Node.js (un servidor basado en JavaScript) o Twisted para Python. 14.1.1 UN SIMPLE SERVIDOR PARA EVENTSOURCE El siguiente código muestra como crear un servidor muy simple con Node.js, el cual acepta conexiones y envía mensajes a los clientes conectados. En este caso, únicamente se notifica al resto de usuarios conectados al servicio, que un nuevo usuario se ha conectado. va htepi re quites (nta) http.createServer (function (reg, res) ( res.writeHead(200, ('Content-Type': 'text/event-stream', ¡Sache control NO SC acietan, // get the last event id and convert to a number var lastld = req.headers['last-event-id']*1; IN (AS) more (ueno dl. = lesule. dl < yeauales dls) res.write('data: ' + JSON.stringify(historyl[eventld]) + UNiaatels 13 Svanele se Viva)? ) ) // finally cache the response connection connections.push(res); // When a regular web request is received connections.forEach(function (response) ( history [++eventld] = [ agent: reg.headers['user-agent'], time: +new Date )P; res.write('data: ' + JSON.stringify(history[eventld]) + Nimes Y + wentae + mi), 0 listen (ss, "1270.01 %)7 comsule. los (SS cua cue Juice dar. 0.0.t1S57/0) E En el lado del cliente, el código sería tan sencillo como el siguiente: var es = new EventSource ('/eventsource'); s.onmessage = function (event) (

var data = JSON.parse(event.data); log.innerHTML += AE + + data.agent '"
connected at ' + (new Date(data.time)) + A 1 Una aplicación muy simple, pero que nos da una idea del funcionamiento de los eventos en tiempo real, utilizando un servidor basado en eventos. ÍNDICE DE CONTENIDOS EventSource 14.1 EventSource en el servidor

— Anterior Siguiente => CAPÍTULO 15 FILE HTML5 ofrece una forma estándar de interactuar con archivos locales a través de la especificación del API de archivos. El API de archivos se puede utilizar, por ejemplo, para crear una vista previa en miniatura de imágenes mientras se envían al servidor o para permitir que una aplicación guarde una referencia de un archivo mientras el usuario se encuentra sin conexión. También se podría utilizar para verificar si el tipo MIME de un archivo seleccionado por el usuario coincide con los formatos de archivo permitidos o para restringir el tamaño de un fichero, antes de enviarlo al servidor. A continuación se indican las interfaces que ofrece la especificación para acceder a archivos desde un sistema de archivos local: e File: representa un archivo local y proporciona información únicamente de lectura (el nombre, el tamaño del archivo, el tipo MIME y una referencia al manejador del archivo). e FileList: representa un conjunto de objetos File (tanto para un conjunto de ficheros seleccionados a través de como para un conjunto de ficheros arrastrados desde el sistema de ficheros al navegador). e Blob: permite fragmentar un archivo en intervalos de bytes. Cuando se utiliza junto con las estructuras de datos anteriores, el API de FileReader se puede utilizar para leer un archivo de forma asíncrona mediante el control de eventos de JavaScript. Por lo tanto, se puede controlar el progreso de una lectura, detectar si se han producido errores y determinar si ha finalizado una carga de un fichero. El modelo de evento de FileReader guarda muchas semejanzas con el AP| de xMLHttpRequest . 15.1 DETECCIÓN DE LA FUNCIONALIDAD En primer lugar, se debe comprobar que el navegador sea totalmente compatible con el API de archivos. Si la aplicación solo va a utilizar algunas funcionalidades del API, se debe modificar este fragmento de código para adaptarlo a nuestras necesidades: // Check for the various File API suppca aL se (window.File ££ window.FileReader ££ window.FileList ££% window.Blob) ( // Great success! All the File APIs are supported + else ( alert ('The File APIs are not fully supported in this browser.');

15.2 ACCESO A TRAVÉS DEL FORMULARIO La forma más sencilla de cargar un archivo es utilizar un elemento estándar de formulario. JavaScript devuelve la lista de objetos File seleccionados como un objeto FileList. A continuación, se muestra un ejemplo en el que se utiliza el atributo multiple para permitir la selección simultánea de varios archivos: function handleFileSelect (e) ( var files = e.target.files; // Filelist object // files is a FileList of File objects. List some properties. arto out a mor (eve Ll = 0, pp e. == ldes [sip ee) A output spust ats'., escapeltr.name), .s (0, ttype in O f.size, ' bytes, last modified: ' Y f.lastModifiedDate.toLocaleDateString(), '1i>'); liston = "Sul" + Otiejatie. Omar) + S/ul>!, files.addEventlListener('change', handleFileselect, false); 15.3 CÓMO LEER ARCHIVOS Después de obtener una referencia de File, podemos crear una instancia de un objeto FileReader para leer su contenido y almacenarlo en memoria. Cuando finaliza la carga, se lanza el evento onload y se puede utilizar su atributo result para acceder a los datos del archivo. A continuación se indican las cuatro opciones de lectura asíncrona de archivo que incluye FileReader! e FileReader.readAsBinaryString(Blob|File): la propiedad result contendrá los datos del archivo/objeto BLoB en forma de cadena binaria. Cada byte se representa con un número entero comprendido entre 0 y 255, ambos incluidos. e FileReader.readAsText (Blob|File, opt_encoding): la propiedad result contendrá los datos del archivo/objeto BLoB en forma de cadena de texto. De forma predeterminada, la cadena se decodifica con el formato utr-8. Podemos especificar un parámetro de codificación opcional para especificar un formato diferente.

e FileReader.readAsDataURL(Blob|File): la propiedad result contendrá los datos del archivo/objeto BLoB codificados como una URL de datos. e FileReader.readAsArrayBuffer (Blob|File): la propiedad result contendrá los datos del archivo/objeto BLoB como un objeto ArrayBuffer. Una vez que se ha activado uno de estos métodos de lectura en el objeto FileReader, se pueden escuchar los eventos onloadstart, onprogress, onload, onabort, onerror Y onloadend para realizar un seguimiento de su progreso de lectura. En el ejemplo que se muestra a continuación, obtenemos las imágenes de los elementos seleccionados por el usuario, leemos su contenido con reader.readAsDataURL() mostramos una miniatura de la imagen: function handleFileSelect (evt) ( var files = evt.target.files; // FileList object // Loop through the Filelist and render image files as thumbnails. so (eve al = 0, 9 E = sales [ss se) Y // Only process image files. EN pe mate ni(Miima ges) continue; var reader = new FileReader (); // Closure to capture the file information. reader.onload = (function(theFile) ( return function(e) ( // Render thumbnail. var span = document .createElement ('span'); span.innerHTML = [''].joi list.insertBefore(span, null); E // Read in the image file as a data URL. reader.readAsDataURL(f);

files.addEventlListener('change', handleFileselect, false); 15.4 FRAGMENTACIÓN DE ARCHIVOS En algunos casos, leer el archivo completo en memoria no es la mejor opción. Supongamos, por ejemplo, que se quiere crear una herramienta de subida de archivos de forma asíncrona. Para acelerar la subida, se podría leer y enviar el archivo en diferentes fragmentos de bytes. El servidor se encargaría de reconstruir el contenido del archivo en el orden correcto. Afortunadamente, la interfaz File nos proporciona un método de fragmentación de ficheros. El método utiliza un byte de inicio como primer argumento, un byte de finalización como segundo argumento. El siguiente ejemplo muestra cómo leer un fichero por partes: var files = document .getElementByld('files').files; e (miles. lencia) 4 alert ('Please select a file!'); cSurbiaae ) veis ele = iiles[01+ var start = 0; var stop = file.siz 7 var reader = new FileReader (); reader.onloadend = function(e) ( if (e.target.readyState == FileReader.DONE) ( // DONE == 2 y] document .getElementByld ('byte_content') .textContent = e.target.result; document .getElementByld ('byte_range').textContent = SIRO NESST ES E ES O O SES O IS OA (O) y; ae (mile meadklersllics) 4 var blob = file.webkitSlice(start, stop + 1); ) else 1£ (file.mozSlice) ( var blob = file.mozSlice(start, stop + 1); ) reader.readAsBinaryString (blob); ÍNDICE DE CONTENIDOS File

15.1 Detección de la funcionalidad 15.2 Acceso a través del formulario 15.3 Cómo leer archivos 15.4 Fragmentación de archivos

— Anterior Siguiente => CAPÍTULO 16 HISTORY El API history de HTML es la manera estándar de manipular el historial de navegación a través de JavaScript. Partes de esta API ya se encontraban disponibles en versiones anteriores de HTML. Ahora, HTML5 incluye una nueva manera de añadir entradas al historial de navegación, modificando la URL pero sin actualizar la página actual, y eventos que se disparan cuando el usuario a eliminado estas entradas, pulsando el botón de volver del navegador. Esto quiere decir que la barra de direcciones sigue funcionando de la misma manera, identificando los recursos de manera única, aún cuando las aplicaciones hacen un uso intensivo de JavaScript sin recargar la página. Como sabemos, una URL representa un recurso único. Podemos enlazarlo directamente, almacenarlo como favorito, los motores de búsqueda pueden analizar su contenido, podemos copiarlo y enviarlo por email... La URL realmente importa. Así pues, lo que queremos es que contenidos únicos dispongan de una URL única. Hasta ahora, el comportamiento normal de los navegadores recargar de nuevo la página si modificábamos la URL, realizando una nueva petición y obteniendo de nuevo todos los recursos del servidor. No había manera de decir al navegador que cambiase la URL pero descargase únicamente la mitad de la página. El API history de HTML5 permite precisamente esto. En lugar de solicitar la carga de toda la página, podemos utilizar JavaScript para cargar únicamente los contenidos que deseemos. La idea es la siguiente. Imaginemos que tenemos una página A y otra página B, que comparten el 90% de su contenido. Cuando un usuario se encuentra en la página A, y quiere navegar a la B, lo normal es realizar una petición completa. En lugar de realizar esta petición, interrumpimos esta navegación y realizamos los siguientes pasos de manera manual: 1. Cargar el 10% de contenido diferente de la página B, a través de algún método como AJAX. 2. Cambiar el contenido, utilizando innerHTML U otros métodos del DOM. Es posible que tengamos que reiniciar los eventos asociados a los elementos. 3. Actualizamos la URL del navegador, indicando la dirección de la página B, utilizando el API history de HTML5. Tras realizar estos pasos, disponemos de un DOM exacto al de la página B, como si hubiésemos navegado hasta ella, pero sin realizar una petición completa.

16.1 API El API de HTML4 ya incluía algunos métodos básicos para movernos a través del historial de navegación, como eran history.back ();, history.forward() Y history.go(n). Sin embargo, estos métodos no permitían modificar la pila del historial, por lo que no eran de gran utilidad. HTML5 ha introducido dos nuevos métodos que nos permiten añadir y modificar las entradas del historial, concretamente history .pushState() y history.replaceState(). Además de estos métodos, se ha añadido también un evento window.onpopstate, que es lanzado cada vez que alguna de las entradas de history cambia. 16.1.1 MÉTODO PUSHESTATE () Supongamos que estamos visitando http: //www.arkaitzgarro.com/html5/index.html y a través de un script realizamos la siguiente operación: Man st ar SONS O Oo history.pushState(state0bJ, "Demos", "demos.html"); Esto va a provocar que en la barra de direcciones se muestre http://www.arkaitzgarro.com/html5/demos.html, pero el navegador no va a cargar demos .html1 ni va a comprobar su existencia. En este punto, si navegamos a otra página como http: //www.google.es/, y después presionamos el botón de volver, en la URL se mostrará http: //www.arkaitzgarro.com/html15/demos.html y la página lanzará el evento popstate, donde el estado contiene una copia de stateobj. La página que se mostrará será index.html, pero deberemos realizar un trabajo extra al lanzarse el evento para mostrar el contenido correcto. El método pushState () toma tres parámetros: un objeto de estado, un título y una URL: e El objeto de estado: es un objeto de JavaScript asociado con la nueva entrada del historial creada con pushState (). Cada vez que el usuario navega al estado creado, el evento popstate es disparado, y la propiedad state del evento contiene una copia de este objeto. Este objeto puede representar cualquier que se pueda serializar. Como este objeto se almacena en el disco, es posible recuperarlo aunque el navegador se cierre. Los navegadores imponen un límite de tamaño a la hora de almacenar estados (en el caso de Firefox 640kB). Si se necesita más espacio, es recomendable utilizar sessionStorage O localStorage. e El título: representa el nuevo título de la página a la que navegamos. e La nueva URL: corresponde con la nueva URL que se añade al historial de navegación. Esta URL puede ser absoluta o relativa, la única restricción es que corresponda al dominio del documento actual. Si no se especifica este parámetro, la URL corresponde con el documento actual.

En esencia, ejecutar el método pushstate() es similar a definir window. location = "foo", ya que en ambos casos se crea y activa una nueva entrada en el historial asociada con el documento actual. Pero pushState () ofrece las siguientes ventajas: e La nueva URL puede ser cualquier URL dentro del dominio actual. En cambio, window.location = "*foo" se mantiene siempre en el documento actual. e No es necesario cambiar la URL actual para añadir una nueva entrada y almacenar datos asociados. e Podemos asociar datos a una nueva entrada en el historial. Con el enfoque basado en hash (+4), los datos tenemos que añadirlos a la URL. 16.1.2 MÉTODO REPLACESTATE () El método history.replacesState () funciona de manera similar a history.pushState (), a excepción de que replacestate() modifica la entrada actual del historial, en lugar de añadir una nueva. Éste método es útil cuando queremos actualizar el objeto de estado de la entrada actual en respuesta a una acción del usuario. 16.1.3 EVENTO POPSTATE El evento popstate es lanzado cada vez que la entrada actual del historial cambia por otra entrada existente en el mismo documento. Si la entrada del historial que está siendo activada fue creada a través de history .pushState () O se modificó con history.replaceState(), el evento popstate recibe como parámetro una copia del estado de la entrada del historial. Éste evento no se lanza cuando se llama a history.pushState () O history.replacestate (). Únicamente se dispara realizando una acción en el navegador como pulsando el botón atrás o ejecutando history.back() en JavaScript. Un ejemplo de este comportamiento: window.onpopstate = function (event) ( alert (document .location + ", state: " + JSON.stringify(event.state)); y; history.pushState((page: 1), "title 1", "?page=1"); history.pushState((page: 2), "title 2", "?page=2"); history.replaceState(([page: 3), "title 3", "?page=3"); // alerts "http://example.com/index.html?page=1 state pager cia history bació(s // alerts "http://example.com/index.html, state: null istorybacia (0 alerts "http: //example.com/index.h ASCO ot) A

Cuando la página se carga, por ejemplo al reiniciar el navegador, tango Chrome como Safari lanzan el evento popstate, pero no es el caso de Firefox. Sin embargo, en este caso, es posible acceder a los datos almacenados en pushState desde la propiedad state del objeto history. window.onload = function() ( var currentState = history.state; ÍNDICE DE CONTENIDOS History 16.1 API

— Anterior Siguiente => CAPÍTULO 17 XMLHTTPREQUEST2 XMLHttpRequest forma parte de las mejoras incrementales que los creadores de navegadores están implementando a la plataforma base. XMLHttpRequest de nivel 2 introduce una gran cantidad de nuevas funciones que ponen fin a los problemas de nuestras aplicaciones web, como solicitudes de origen cruzado, eventos de progreso de subidas y compatibilidad con subida/bajada de datos binarios. Esto permite a AJAX trabajar en coordinación con muchas de las API HTML5 más punteras, como API de FileSystem, el API de Web Audio y WebGL. 17.1 RECUPERACIÓN DE ARCHIVOS Recuperar archivos como blob binario era muy complicado con xÍHr. Técnicamente, no era ni siquiera posible. Un truco que se ha documentado mucho implicaba anular el tipo mime con un conjunto de caracteres definido por el usuario, como se muestra a continuación. La antigua forma de recuperar una imagen: var xhr = new XMLHttpRequest (); NEO enMi paltas O/amage pagina ue)e // Hack to pass bytes through unprocessed. xhr.overrideMimeType ('text/plain; charset=x-user-defined'); xhr.onreadystatechange = function(e) ( if (this.readyState == 4 £€£ this.status == 200) ( var binSstr = this.responseText; moje (eve al =010, dea = Jebtasieiós Lemoa 1. << leas ¿al A var cc = binStr.charCodeat (1); Sian ga ronehanSodelc Dt) Van Hoyts 10 y ES arios St ll y; xhr.send(); Aunque funciona, lo que se obtiene realmente en responseText no es un blob binario,

sino una cadena binaria que representa el archivo de imagen. Estamos engañando al servidor para que devuelva los datos sin procesar. 17.2 ESPECIFICACIÓN DE UN FORMATO DE RESPUESTA En lugar de realizar la acción del ejemplo anterior, vamos a aprovechar las nuevas propiedades de XMLHttpRequest ( responseType Y response) para indicar al navegador el formato en el que queremos que nos devuelva los datos. e xhr.responseType: antes de enviar una solicitud, establece xhr.responseType en text, arraybuffer, blob O document, en función de los datos que necesites. Ten = '+ (o si se omite), se utilizará la en cuenta que si se establece xhr.responseType respuesta predeterminada text. e xhr.response: después de una solicitud correcta, la propiedad response de xhr DOMString, ArrayBuffer, Blob O Document contendrá los datos solicitados como 1 (en función del valor establecido para responseType). Buffer en lugar de como una Con esto, podemos recuperar la imagen como Array! cadena. Al transferir el búfer al API Bl1obBuilder se crea un Blob: window.WebKitBlobBuilder || window.BlobB BlobBuilder = window.MozBlobBuilder | uilder; var xhr = new XMLHttpRequest (); xt open (CEI aten tto/amager pag, enle) xhr.responselType = 'arraybuffer'; xhr.onload = function(e) ( if (this.status == 200) ( var bb = new BlobBuilder (); bb.append (this.response); // Note: not xhr.responseText var blob = bb.getBlob('image/png'); y; xhr.send(); Si se quiere trabajar directamente con un Blob o no se necesita manipular ni un solo byte del archivo, utilizaremos xhr: responseType='blob': window.URL = window.URL || window.webkitURL; // Take care of vendor prefixes.

var Sola OE xhr y; OE y 17. xhr = new XMLHttpRequest (); OPE pata ito imagen page nue)" .responseType = 'blob'; .onload = function(e) ( if (this.status == 200) ( var blob = this.response; var img = document .createElement ('img'); img.onload = function(e) ( window.URL.revoke0bjJectURL(img.src); // Clean up after yourself. 1 img.src = window.URL.createO0bjectURL (blob); document .body .appenaCchild (img); ) send (); 3 ENVÍO DE DATOS Durante algún tiempo, XMLHttpRequest nos ha limitado a enviar datos DOMString O Document (XML). Pero eso se acabó. Se ha anulado un método sena () y rediseñado para aceptar todos estos tipos: DOMString, Document, FormData, Blob, File y ArrayBuffer. Envío de la cadena de datos: xhr.send (domstring) sendText ('test string'); function sendTextNew (txt) ( var xhr = new XMLHttpRequest (); AMO SM OS IS SCI LS) E xhr.responseType = 'text'; xhr.onload = function(e) ( if (this.status == 200) ( console.log(this.response); y; NAS mai) sendText2('test string'); e Envío de formularios: xhr.send(formdata)

function sendFormí() ( var formData = new FormData(); E formData.append ('username', 'johndoe'); formData.append('id', 123456); var xhr = new XMLHttpRequest (); OPE (POSTS even, turue)e: imei loro. > TEO ea) E as e xhr.send(formData); Por supuesto, no es necesario crear un objeto

desde cero. Los objetos Forn! se pueden inicializar a partir de un elemento HTMLFormElement de la página. Por ejemplo:

function sendForm(form) ( var formData = new FormData (form); formData.append ('secret_token', '1234567890'); var xhr = new XMLHttpRequest (); MITO PS BOS IA ESO eMac talon Ea ueS) MO MO ANCONS xhr.send(formData); return false; // Prevent page from submitting. Data Un formulario HTML puede incluir subidas de archivos (como ) y FormData también. Simplemente se añade el archivo o los archivos y el navegador construirá una solicitud multipart/form-data cuando se ejecute sena (): function uploadFiles (url, files) ( var formData = new FormDatal(); ES moje ele 1. == 0, miles. mile = miles (ae Sepa Al ¿e formData.append (file.name, file);

var xhr = new XMLHttpRequest (); NE OSO OSI cl aus) sine O Loro! == Ebincicdon iS) Loss xhr.send(formData); // multipart/form-data document .querySelector ('input [type="file"]').addEventlisten (SA uploadFiles('/server', this.files); a ES). 17.4 SUBIDA DE ARCHIVOS O BLOB También podemos enviar datos de rile O Blob CON XHR. er('change', functio En este ejemplo se crea un texto nuevo desde cero con el API 10b1 eseBlob” al servidor. El código también configura un controlador usuario sobre el progreso de la subida: function upload (bloborFile) ( var xhr = new XMLHttpRequest (); xo pene LOs Semen, tic lue)e: sine omo. => EuacciontiS) $ ss 1 // Listen to the upload progress. var progressBar = document .querySelector ('progress'); xhr.upload.onprogress = function(e) ( if (e.lengthComputable) ( progressBar.value = (e.loaded / e.total) * 100; pPROJRes'si orted browsers. ) y; ns en aliBlobOEte)e: Builder y se sube para informar al Bar.textContent = progressBar.value; // Fallback for unsupp // Take care of vendor prefixes. BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window. BlobBuilder; var bb = new BlobBuilder ();

bb.append('hello world'); upload (bb.getBlob('text/plain')); 17.5 SUBIDA DE UN FRAGMENTO DE BYTES Y por último, podemos enviar ArrayBuffer como la carga de XHR. function sendArrayBuffer () ( var xhr = new XMLHttpRequest (); di ARM AOS | 1 SSIASiE y, US) E sima omo! = nace ea) dl 0 e val ulints Array = new Ulints Array ia, Se xhr.send(ulnt8Array.buffer); 17.6 EJEMPLOS PRÁCTICOS 17.6.1 CÓMO DESCARGAR Y GUARDAR ARCHIVOS EN EL SISTEMA DE ARCHIVOS HTML5 Supongamos que tienes una galería de imágenes y quieres recuperar un grupo de imágenes para, a continuación, guardarlas localmente con el sistema de archivos HTML5. Una forma de conseguir esto sería solicitar imágenes como ArrayBuffer, Crear un Blob a partir de los datos y escribir el blob con FileWriter: window.requestFileSystem = window.requestFileSystem || window.webkitRequestFil eSystem; loci oja (olaimicaaoa (US). COMS OMS lO TREO RS) var xhr = new XMLHttpRequest (); xhr.open('GET', '/path/to/image.png', true); xhr.responselype = 'arraybuffer'; xhr.onload = functionl(e) ( window. requestFileSystem(TEMPORARY, 1024 * 1024, function(fs) ( ES da fs.root.getFile('image.png', (create: true), function(fileEntry) ( fileEntry.createWriter (function (writer) (

The text on this page is estimated to be only 74.36% accurate

clic. OMMalrEs == Pinto) $ om. e WiolecE., Omega: = astron) os e var bb = new BlobBuilder (); bb.append (xhr.response); writer.write (bb.getBlob('image/png')); ¡AO MO 13) e: NON EBRO) ARO MENA O) e y; NA SENA 17.6.2 CÓMO DIVIDIR UN ARCHIVO Y SUBIR CADA FRAGMENTO Con las API de archivo, podemos minimizar el trabajo necesario para subir un archivo de gran tamaño. La técnica es dividir el archivo que se va a subir en varios fragmentos, crear Un XHR para cada parte y unir los fragmentos en el servidor. Es similar a la forma en que Gmail sube archivos adjuntos tan grandes en tan poco tiempo. window.BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder; function upload (bloborFile) ( var xhr = new XMLHttpRequest (); MOE BOS is Sven ale): sino Oiallosi! = naciona) sos ds xhr.send(blobOorFile); document .querySelector ('input [type="file"]').addEventlistener ('change', functio A Mario lobe= ABS ate [001E const BYTES_PER_CHUNK = 1024 * 1024; // 1MB chunk sizes. CONS iSlZ e OO Saiz e: var start = 0; Var tena BYTES ERE UNE while(start < SIZE) (

de (Amor Lics" ía loco) var chunk = blob.mozSlice(start, end); + else ( var chunk = blob.webkitSlice (start, end); upload (chunk) ; start = end; end = start + BYTES_PER_CHUNK; ÍNDICE DE CONTENIDOS XMLHttpRequest2 17.1 Recuperación de archivos 17.2 Especificación de un formato de respuesta 17.3 Envío de datos 17.4 Subida de archivos o Blob 17.5 Subida de un fragmento de bytes 17.6 Ejemplos prácticos

). Descargar página web. 18.2 CAPÍTULO 3 18.2.1 EJERCICIO 2 Crear un formulario que contenga lo siguiente: e Los 12 nuevos tipos de elementos input. e El nuevo elemento datalist, que contenga algunos nombres de provincia y un campo de texto que se relacione con él. Una caja de texto (), a la cual aplicar los atributos autofocus, placeholder, required Y autocomplete. Una caja de texto que sólo pueda contener números (), cuyos valores tienen que estar comprendidos entre 0 y 10. Un campo de selección de ficheros (), al que aplicar el atributo multiple. Un campo de introducción de password (), donde el valor introducido debe cumplir lo siguiente: debe tener una longitud mínima de 8 caracteres, comenzar por un número y terminar en una letra mayúscula. Un nuevo elemento progress que represente el avance de completado de campos del formulario. Acceder al formulario desde al menos 4 navegadores (2 de escritorio y 2 de dispositivos móviles), y comprobad el comportamiento y funcionamiento en cada elemento del formulario. Anotad dichos resultados en una hoja de cálculo para futuras referencias.

18.3 CAPÍTULO 4 18.3.1 EJERCICIO 3 Identificar las siguientes características de al menos 4 navegadores (2 de escritorio y 2 de dispositivos móviles): e Cuáles de los 12 nuevos tipos de input soporta el navegador. e Qué codecs de reproducción de vídeo soporta cada navegador. e Qué sistema(s) de almacenamiento local soporta cada navegador. 18.3.2 EJERCICIO 4 Identificar si el navegador soporta el atributo placeholder. En caso de no soportar dicha funcionalidad, cargar el polyfill correspondiente para añadir dicha funcionalidad al navegador. 18.4 CAPÍTULO 5 18.4.1 EJERCICIO 5 A partir del siguiente HTML, realizar los siguientes pasos:

Arkaitz Garro

ata-lang="en" data-food="Bacon">John Doe1li> E da

Divya Resig1li> e Obtener cada uno de los atributos data- de los elementos de la lista, y mostrarlos por consola. e Modificar el idioma es por es_ES. e Eliminar los elementos de la lista cuyo atributo data-delete Sea true. 18.5 CAPÍTULO 6 18.5.1 EJERCICIO 6 Crear un reproductor de vídeo que cumple las siguientes características: e Reproducir los vídeos independientemente del codec soportado por el navegador. e Incluir controles de reproducción, pausa, parar, avanzar y retroceder 10 segundos, inicio y fin.

e Control de volumen y paso a pantalla completa. e Un indicador de progreso de la reproducción. Añadir una lista de reproducción que permita seleccionar un nuevo vídeo, y éste se reproduzca sin recargar la página. Figura 18.1 Aspecto final del reproductor 18.6 CAPÍTULO 7 18.6.1 EJERCICIO 7 Dibujar sobre un elemento canvas, un stickman con un aspecto final similar al que se muestra a continuación. Seguir las siguiente indicaciones como ayuda: e El tamaño inicial del canvas es de 200px del ancho y 300pxde alto. e Utilizar un rectángulo negro para pintar todo el fondo del canvas. e Dibujar la cabeza con un arco completo, en las coordenadas (100,50), y un radio de 30px. e La sonrisa corresponde con un semiarco rojo (+coo), con inicio de coordenadas (100,50) y un radio de 20px. Los ojos son dos circunferencias rojas situadas en las coordenadas (90,45) y

(110,45) y de radio 3px. 5 600 Ejercicio canvas Mostrar un menú Figura 18.2 Resultado final del stickman 18.7 CAPÍTULO 8 18.7.1 EJERCICIO 8 Implementad las siguientes funcionalidades utilizando SessionStorage Y LocalStorage: e Crear una caja de texto, a modo de editor de contenidos, y utilizando SessionStorage almacenar el contenido de la caja en cada pulsación de tecla. Si la página es recargada, el último contenido almacenado debe mostrarse en la caja de texto. Comprobad que cerrando la pestaña actual, o abriendo una nueva ventana, los datos no se comparten. e Modificar el código anterior para utilizar LocalStorage. Comprobad que en este caso, aunque cierre la ventana o abra una nueva, los datos se mantienen. Añadir la posibilidad de actualizar el resto de ventanas abiertas, cada vez que se modifique el valor de la caja de texto en cualquiera de ellas. 18.7.2 EJERCICIO 9 Crear un objeto que encapsule una base de datos WebSQL, que nos permitar acceder a una base de datos para añadir, modificar, eliminar y obtener registros. Dicha base de datos va a almacenar tweets procedentes de Twitter, que tienen asociado el hashtag *htmi5. Los requisitos son los siguientes:

e Disponer de una tabla para almacenar los tweets. Los campos mínimos son: identificador del tweet, texto, usuario, y fecha de publicación. e Disponer de una tabla para almacenar los usuarios que publican los tweets. Esta tabla debe estar relacionada con la anterior. Los campos mínimos son: identificador del usuario, nombre e imagen. e Crear un método addTweet que dado un objeto que corresponde con un tweet, lo almacene en la base de datos. Almacenar el usuario en caso de que no exista, o relacionarlo con el tweet si existe. e Crear un método removeTweet que dado un identificador de tweet, lo elimine de la base de datos. Éste método debe devolver el tweet eliminado. e Crear un método updateTweet que dado un objeto que corresponde con un tweet, actualice los datos correspondientes al tweet en la base de datos. e Crear un método getTweets que dado un parámetro de fecha, me devuelva todos los tweets posteriores a esa fecha. Cada tweet debe incluir sus datos completos y el usuario que lo creó. Obtener los últimos 25 tweets que tienen como hashtag +thtml5 de la siguiente consulta a Twitter: http: //search.twitter.com/search.json? q=%23html58rpp=256result_type="recent" Consultad la API de Twitter para identificar el formato del resultado, nombres de campos, ete. 18.7.3 EJERCICIO 10 Crear un objeto que encapsule una base de datos IndexedDB, que nos permitar acceder a una base de datos para añadir, modificar, eliminar y obtener registros. Dicha base de datos va a almacenar una sencilla lista de tareas pendientes. Los requisitos son los siguientes: e Disponer de un almacén de tareas pendientes. Sus propiedades son: un identificador único que actúa como índice, el texto descriptivo, una propiedad que nos indique si la tarea está completada o no y la fecha/hora de creación. Crear un método addTask que dado un objeto que corresponde con una tarea, lo almacene en la base de datos. Crear un método removeTask que dado un identificador de una tarea, lo elimine de la base de datos. Éste método debe devolver la eliminada. Crear un método updateTask que dado un identificador de una tarea, actualice los datos correspondientes a la tarea en la base de datos. Crear un método getTasks que dado un parámetro booelano completado, nos devuelva las tareas que se encuentran completadas o no.

18.8 CAPÍTULO 9 18.8.1 EJERCICIO 11 Cread una página HTML que muestre la hora local de vuestro ordenador, y la hora del servidor de www.google.es. Los cálculos de hora local y obtención de hora del servidor, deben crearse en ficheros separados. El comportamiento es el siguiente: e Todos los ficheros necesarios para realizar el ejercicio deben ser cacheados, a excepción del javascript que solicita la petición al servidor. e Las peticiones de hora al servidor www.google.es se realizan a través de Ajax, en intervalos de 1 segundo. Dichas peticiones no deben realizarse si no existe conexión. En tal caso, se muestra un mensaje al usuario indicando que se ha perdido la conexión. e Sise recarga la página, y no existe conexión, utilizar un fallback para la obtención de la hora del servidor, que muestre un mensaje al usuario indicando que se ha perdido la conexión. e00 Mi hora y la hora en www.google.es E. La hora en mi dispositivo es 13:05:55 y la hora en www.google.es es 10:30:48 Mostrar un menú Figura 18.3 Resultado del ejercicio con conexión 600 Mi hora y la hora en www.google.es Ye La hora en mi dispositivo es 13:07:41 y no hay conexión con el servidor Mostrar un menú Figura 18.4 Resultado del ejercicio sin conexión Utilizad el siguiente código para obtener la hora de un servidor: function srvTime (url) (

var xmlHttp = new XMLHttpRequest (); xml1Http.open('HEAD',url, false); xmlHttp.setRequestHeader ("Content-Type", "text/html"); as ena mula) return xmlHttp.getResponseHeader ("Date"); var st = srvTime("https://www.google.es/"); var date = new Date(st); 18.9 CAPÍTULO 10 18.9.1 EJERCICIO 12 Implementar un carrito de la compra que permita arrastrar los productos a la cesta, y calcule el precio total de la compra. El proceso es el siguiente: e Al pasar con el ratón sobre una imagen, el puntero cambia de aspecto (cursor: move; ) y se permite arrastrar el contenido. Al arrastrar el elemento, la zona que contiene la cesta de la compra se ilumina. Al soltar la imagen sobre la cesta de la compra, añade el producto si no existía, mostrando la imagen, el nombre del producto, la cantidad de productos en la cesta (en este caso 1) y el coste total para ese producto. Al soltar la imagen sobre la cesta de la compra, si el producto ya se encontraba en la cesta, actualiza la cantidad de productos y su precio. Posibles mejoras para este ejercicio: e Añadir la posibilidad de eliminar los productos de la cesta de la compra, arrastrándolos desde la propia cesta y soltándolos en cualquier parte de la página. En este caso, mostraríamos un mensaje de confirmación de eliminación del producto. e Mantener una persistencia de datos para la cesta de la compra, que el actualizar la página no se pierdan los productos introducidos. Descargar sitio web.

6009 Carro de la compra Carro de la compra EAU DU SOIR LOVE IN BLACK COUEUR DE FLEUR FLEUR ORIENTAL SISLEY CREED MILLER HARRIS MILLER HARRIS EDF 06€ EDP 100ML 84,00€ EDP 100ML 8: GERANIUM BOURBON OSMANTHUS FRANGIPANI SAMPAQUITA MILLER HARRIS ORMONDE JAYNE ORMONDE JAYNE ORMONDE JAYNE Mostrar un menú Figura 18.5 Aspecto inicial de la cesta de la compra 18.10 CAPÍTULO 11 18.10.1 EJERCICIO 13 Utilizando los servicios de geolocalización, realizar las siguientes tareas: e Solicitar las coordenadas actuales, y mostrar dichas coordenadas (y la precisión) tanto en formato texto como un punto en el mapa. e Haciendo uso del entorno de desarrollo de Android (emulador y SDK) y la herramienta DDMS, indicar al dispositivo una posición GPS concreta. Posteriormente, modificar la implementación para solicitar continuamente la posición del dispositivo. En la herramienta DDMS, utilizar el fichero de rutas GPX que se proporciona y mostrar cada nuevo punto en el mapa. Descargar sitio web.

2.0.0 Geolocalizació » Geolocalización Tu localización: encontrado. — Inteaurrondoko a] dos Kg Geltokia Son | Julimasene Kalea cementerio nicipal Polloe Figura 18.6 Posición actual en el mapa 18.11 CAPÍTULO 12 18.11.1 EJERCICIO 14 Crear un Web worker que dado un número entero, calcule todos los números primos comprendidos entre 1 y dicho número. Proporcionaremos a este Worker un número entero, y devolverá un array con todos los números primos encontrados. Mostrar el listado de números primos en el documento principal.

600 WebWorkers A WebWorkers Introduce un número entero mayor que 1: 1000 : | Calcular Tiempo empleado: 1ms Primos: 235711 1317 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997 Mostrar un menú Figura 18.7 Resultado tras calcular los números primos 18.12 CAPÍTULO 13 18.12.1 EJERCICIO 15 Implementar un servicio de chat, utilizando tecnología Web Socket, a partir del código proporcionado, que se describe a continuación. e Se dispone de un servidor de chat, basado en Node.js, al cual deben conectarse los usuarios del chat. La dirección del servidor es ws: //www.arkaitzgarro.com:1337. e Se proporciona la interfaz básica (HTML y JavaScript) para desarrollar la aplicación. Es necesario implementar la conexión con el servidor y el intercambio de mensajes, así como la actualización de la interfaz. e El protocolo de mensajes es el siguiente: e El primer mensaje a enviar al servidor es el nick. Tomad el valor de la caja de texto y enviarla al servidor como una cadena de texto. e Una vez estamos "registrados" en el servidor, éste puede comenzar a enviarnos mensajes, tanto los existentes hasta el momento, como los nuevos que se produzcan por otros usuarios. Estos mensajes (en formato JSON) corresponden con un objeto JavaScript, cuya estructura se muestra a continuación. e Finalmente, para enviar los mensajes de texto del usuario, enviamos la cadena

de texto directamente al servidor. // Mensaje de tipo "color" ( ESE O data : "" // Valor del color asignado por el servidor // Mensaje de tipo "history" 1 Eos s Units”, // Un array que contiene los últimos mensajes enviados cleia 2 ebiemei, use, cols, mej] // Mensaje de tipo "message" ( type : "message", // Un objeto que contiene cleita Ss [elulmor., ere, EN Descargar sitio web. un mensaje enviado por otro usuario or, time) HTML5 (QA) 16:53: Hey there! 'm using WebSockets. Arkaitz Q) 16:51: Hola mundo! Figura 18.8 Resultado final del c ÍNDICE DE CONTENIDOS Ejercicios 18.1 Capítulo 2 18.2 Capítulo 3 18.3 Capítulo 4 hat

18.4 Capítulo 5 18.5 Capítulo 6 18.6 Capítulo 7 18.7 Capítulo 8 18.8 Capítulo 9 18.9 Capítulo 10 18.10 Capítulo 11 18.11 Capítulo 12 18.12 Capítulo 13