HTML 5
HTML 5
HTML 5
ARKAITZ GARRO
https://www.arkaitzgarro.com/html5/index.html
ARKAITZ GARRO
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).
1.2 5 TIPS
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 <video>,
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í.
<!DOCTYPE html>
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.
<!DOCTYPE html
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!DOCTYPE html>
2.1.2 ELEMENTO RAÍZ HTML
En todo documento HTML, su elemento raíz o nodo superior siempre es la
etiqueta <html>. Hasta ahora, este elemento raíz se definía de la siguiente
manera:
<html xmlns=http://www.w3.org/1999/xhtml
lang="en"
xml:lang="en">
<html lang="en">
<head>
<title>My Weblog</title>
href="/feed/" />
<link rel="search"
type="application/opensearchdescription+xml"
href="opensearch.xml" />
</head>
<meta charset="utf-8">
2.1.3.2 LINKS
Dentro del elemento head, las etiquetas <link> son una manera de acceder
o declarar contenido externo al documento actual, que puede cumplir
distintos objetivos:
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.
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.
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<body>
<div id="header">
<h1>My Weblog</h1>
<p class="tagline">
</p>
</div>
<div id="nav">
<ul>
<li><a href="#">home</a></li>
<li><a href="#">blog</a></li>
<li><a href="#">gallery</a></li>
<li><a href="#">about</a></li>
</ul>
</div>
<div class="articles">
<div class="article">
<h2>
</h2>
<div class="content">
</div>
<div class="comments">
</div>
</div>
<div class="aside">
<div class="related"></div>
<div class="related"></div>
<div class="related"></div>
</div>
<div id="footer">
<p>§</p>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<body>
<header>
<hgroup>
<h1>Title</h1>
<h2 class="tagline">
</h2>
</hgroup>
</header>
<nav>
<ul>
<li><a href="#">home</a></li>
<li><a href="#">blog</a></li>
<li><a href="#">gallery</a></li>
<li><a href="#">about</a></li>
</ul>
</nav>
<section class="articles">
<article>
<h2>
</h2>
<div class="content">
</div>
<section class="comments">
</section>
</article>
</section>
<aside>
<div class="related"></div>
<div class="related"></div>
<div class="related"></div>
</aside>
<footer>
<p>§</p>
</footer>
</body>
</html>
<header>
<h1>Title</h1>
</header>
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 <hgroup>.
<header>
<hgroup>
<h1>Title</h1>
<h2 class="tagline">
</h2>
</hgroup>
</header>
2.4.2 <NAV>
Según la especificación, un elemento <nav> representa lo siguiente:
<nav>
<ul>
<li><a href="#">home</a></li>
<li><a href="#">blog</a></li>
<li><a href="#">gallery</a></li>
<li><a href="#">about</a></li>
</ul>
</nav>
2.4.3 <FOOTER>
Según la especificación, un elemento <footer> representa lo siguiente:
2.4.4 <ARTICLE>
Según la especificación, un elemento <article> representa lo siguiente:
<section>
<h1>Comments</h1>
<article id="c1">
<footer>
</footer>
</article>
<article id="c2">
<footer>
</footer>
</article>
</section>
2.4.5 <SECTION>
A diferencia del elemento <article>, 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 <section> representa lo siguiente:
<article>
<section>
bricks as "souvenirs"</p>
</section>
<section>
</section>
</article>
<article>
bricks as "souvenirs"</p>
</section>
<section>
</section>
</article>
<section>
<article>
<p>blah blah</p>
</article>
<article>
<p>blah blah</p>
</article>
</section>
<section>
<article>
<p>blah blah</p>
</article>
<article>
<p>blah blah</p>
</article>
</section>
2.4.6 <ASIDE>
Según la especificación, un elemento <aside> representa lo siguiente:
2.4.7 <FIGURE>
Según la especificación, un elemento <figure> 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.
<figure>
<figcaption>
</figcaption>
</figure>
Ejercicio 1
Ver enunciado
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.
document.designMode = 'on';
<ul id="vegetable-seeds">
</ul>
2.5.4 DRAGGABLE
Este atributo indica que el elemento indicado puede ser arrastable. Lo
veremos en el capítulo correspondiente.
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.1 TIPO EMAIL
El nuevo tipo <input type="email"> 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.
3.1.2 TIPO URL
El nuevo tipo <input type="url"> 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 tel:555123456.
Figura 3.2 Campo de tipo url en un dispositivo iOS
3.1.3 TIPO DATE
El nuevo tipo <input type="date"> 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.
3.1.4 TIPO TIME
El nuevo tipo <input type="time"> 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.
Figura 3.4 Campo de tipo time en un dispositivo iOS
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.
Figura 3.5 Campo de tipo datetime en un dispositivo iOS
3.1.6 TIPO MONTH
El nuevo tipo <input type="month"> 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.
Figura 3.6 Campo de tipo month en un dispositivo iOS
3.1.7 TIPO WEEK
El nuevo tipo <input type="week"> 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-W07.
Figura 3.7 Campo de tipo week en Google Chrome
3.1.8 TIPO NUMBER
Como es de esperar, el nuevo tipo <input type="number"> 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.
Figura 3.8 Campo de tipo number en un dispositivo iOS
3.1.9 TIPO RANGE
El nuevo tipo <input type="range">, 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.
Figura 3.9 Campo de tipo range en Google Chrome
3.1.10 TIPO TEL
El nuevo tipo <input type="tel">, 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.
3.1.11 TIPO SEARCH
El nuevo tipo <input type="search">, 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.
Figura 3.11 Campo de tipo search en Google Chrome
3.1.12 TIPO COLOR
El nuevo tipo <input type="color">, 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.
Figura 3.12 Campo de tipo color en Google Chrome
3.2.1 ATRIBUTO LIST Y <DATALIST>
La combinación del atributo list y un elemento de tipo <datalist> da
como resultado un campo de texto, donde el usuario puede introducir
cualquier contenido, y las opciones definidas en el <datalist> se muestran
como una lista desplegable. Hay que tener en cuenta que la lista tiene que
estar contenida en un elemento <datalist> cuyo id coincide con el
indicado en el atributo list:
</datalist>
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).
3.2.4 ATRIBUTO REQUIRED
Este atributo puede ser utilizado en un <textarea> 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.
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 <input type="file">, 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.
3.2.7 ATRIBUTOS MIN Y MAX
Como hemos visto en el campo <input type="number">, 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.
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:
3.2.10 ATRIBUTO FORM
Tradicionalmente, los campos de un formulario van incluidos dentro de la
correspondiente etiqueta <form>. 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 <form>.
Con HTML5, los elementos que hasta ahora era obligatorio que estuviesen
contenidos dentro del elemento <form>, 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 id de dicho formulario.
<form id="foo">
<input type="text">
...
</form>
<textarea form="foo"></textarea>
3.3.1 <PROGRESS>
El elemento <progress> 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:
3.3.2 <METER>
El elemento <meter> es muy similar a <progress> (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:
</p>
Figura 3.18 Nuevo elemento meter
Ejercicio 2
Ver enunciado
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.
<script src="/js/lib/vendor/modernizr-custom.min.js"></script>
if (Modernizr.boxshadow) {
} else {
if (Modernizr.canvas) {
} else {
<head>
...
<script src="/js/lib/vendor/modernizr-custom.min.js"></script>
</head>
<body>
<div class="elemento"></div>
</body>
</html>
.elemento{
.boxshadow .elemento{
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.
Modernizr.load({
test: Modernizr.geolocation,
yep : 'geo.js',
nope: 'geo-polyfill.js'
});
Modernizr.load([
// Presentational polyfills
},
// Functional polyfills
nope : 'functional-polyfills.js',
complete : function () {
myApp.init();
},
// Run your analytics after you've already kicked off all the
rest
// of your app.
'post-analytics.js'
]);
Ejercicio 4
Ver enunciado
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 jQuery, 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).
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.
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:
<ul id="vegetable-seeds">
</ul>
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 <li>, ahora podemos mostrar esta información al instante sin
tener que preocuparnos de hacer ninguna llamada AJAX y sin tener que
hacer ninguna consulta a las bases de datos del servidor.
W3C Specification
Y éstas algunas de las situaciones para las que no se deben usar los data
attributes:
<script>
</script>
<script>
plant.dataset.leaves = null;
Ejercicio 5
Ver enunciado
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?
<param name="movie"
value="http://www.youtube.com/v/9sEI1AUFJKw&hl=en_GB&fs=1&"></para
m>
<embed
src="http://www.youtube.com/v/9sEI1AUFJKw&hl=en_GB&fs=1&"
type="application/x-shockwave-flash"
allowscriptaccess="always"
</object>
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:
6.1.2 AUTOPLAY
Si bien podemos indicar al navegador que reproduzca el vídeo de manera
automática una vez se haya cargado la página, en realidad no es una
buena práctica, ya que a muchos usuarios les parecerá una práctica muy
intrusiva. Por ejemplo, los usuarios de dispositivos móviles, probablemente
no querrán que el vídeo se reproduzca sin su autorización, ya que se
consume ancho de banda sin haberlo permitido explícitamente. No
obstante, la manera de hacerlo es la siguiente:
</video>
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:
</video>
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.
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:
</video>
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.
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.
</video>
6.1.9 SRC
Al igual que en elemento <img>, 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.
Opera Sí No Sí
Firefox Sí Sí Sí
Chrome Sí No Sí
IE9+ No Sí No
Safari No Sí No
<video controls>
</p>
</video>
<video controls>
<source src="lo-res.mp4">
</video>
6.3 API MULTIMEDIA
Los elementos multimedia <video> y <audio> 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:
networkState emptied
preload stalled
buffered play
readyState loadedme
seeking loadeddat
controls waiting
controls playing
Atributos Métodos Eventos
volume canplay
muted canplayth
tracks seeking
tracks seeked
currentTime ended
startTime ratechang
muted
paused
defaultPlaybackRate
playbackRate
played
seekable
ended
autoplay
Atributos Métodos Eventos
loop
video.addEventListener('canplay', function(e) {
this.volume = 0.4;
this.currentTime = 10;
this.play();
}, false);
#myelement
width: 500px;
#myelement:full-screen
width: 100%;
#myelement:full-screen img
width: 100%;
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 controlso 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:
<audio src="audio.mp3">
</audio>
Opera No No Sí Sí
Firefox No No Sí Sí
Chrome Sí Sí Sí Sí
IE9+ Sí Sí No N
Safari Sí Sí Sí N
<audio controls>
</audio>
Ejercicio 6
Ver enunciado
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.
<html>
<head>
<script type="application/javascript">
window.onload = function() {
if (canvas.getContext) {
ctx.fillStyle = "rgb(200,0,0)";
};
</script>
</head>
<body>
</body>
</html>
ctx.fillRect(25,25,100,100);
ctx.clearRect(45,45,60,60);
ctx.strokeRect(50,50,50,50);
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.
context.beginPath();
context.closePath();
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.
// Triángulo relleno
ctx.beginPath();
ctx.moveTo(25,25);
ctx.lineTo(105,25);
ctx.lineTo(25,105);
ctx.closePath();
ctx.fill();
// Triángulo trazado
ctx.beginPath();
ctx.moveTo(125,125);
ctx.lineTo(125,45);
ctx.lineTo(45,125);
ctx.closePath();
ctx.stroke();
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).
for(var i=0;i<4;i++){
for(var j=0;j<3;j++){
ctx.beginPath();
ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise);
if (i>1){
ctx.fill();
} else {
ctx.stroke();
Nota
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.
ctx.beginPath();
ctx.closePath();
ctx.fill();
ctx.fillStyle = '#FFF';
ctx.beginPath();
ctx.arc(75,75,35,0,Math.PI,false); // boca (dextrógiro)
ctx.closePath();
ctx.fill();
ctx.moveTo(65,65);
ctx.beginPath();
ctx.closePath();
ctx.fill();
ctx.moveTo(95,65);
ctx.beginPath();
ctx.closePath();
ctx.fill();
7.4 COLORES
Si queremos aplicar colores a una forma, hay dos características
importantes que podemos utilizar: fillStyle 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.
ctx.fillStyle = "orange";
ctx.fillStyle = "#FFA500";
ctx.fillStyle = "rgb(255,165,0)";
ctx.fillStyle = "rgba(255,165,0,1)";
Ejemplo de fillStyle:
function draw() {
+ Math.floor(255-42.5*j) +
',0)';
ctx.fillRect(j*25,i*25,25,25);
Ejemplo de strokeStyle:
function draw() {
+ ',' + ath.floor(255-
42.5*j) + ')';
ctx.beginPath();
ctx.arc(12.5+j*25,12.5+i*25,10,0,Math.PI*2,true);
ctx.stroke();
}
Los patrones, por otra parte, permiten definir una imagen como origen y
especificar el patrón de repetido, de nuevo de manera similar a como se
realizaba con la propiedad background-image de CSS. Lo que hace
interesante al método createPattern es que como origen podemos utilizar
una imagen, un canvas o un elemento de vídeo.
gradient.addColorStop(0, '#fff');
gradient.addColorStop(1, '#000');
ctx.fillStyle = gradient;
Los degradados radiales son muy similares, con la excepción que definimos
el radio después de cada coordenada:
gradient = ctx.createRadialGradient(canvas.width/2,
canvas.height/2,
0,
canvas.width/2,
canvas.height/2,
150);
gradient.addColorStop(0, '#fff');
gradient.addColorStop(1, '#000');
ctx.fillStyle = gradient;
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.
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
img.onload = function () {
};
img.src = 'avatar.jpg';
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.
function draw() {
// dibujar fondo
ctx.fillStyle = '#FD0';
ctx.fillRect(0,0,75,75);
ctx.fillStyle = '#6C0';
ctx.fillRect(75,0,75,75);
ctx.fillStyle = '#09F';
ctx.fillRect(0,75,75,75);
ctx.fillStyle = '#F30';
ctx.fillRect(75,75,150,150);
ctx.fillStyle = '#FFF';
ctx.globalAlpha = 0.2;
ctx.beginPath();
ctx.arc(75,75,10+10*i,0,Math.PI*2,true);
ctx.fill();
7.7 TRANSFORMACIONES
Al igual que tenemos la posibilidad mover el lápiz por el canvas con el
método moveTo, podemos definir algunas transformaciones como rotación,
escalado, transformación y traslación (similares a las conocidas de CSS3).
7.7.1 MÉTODO TRANSLATE
Éste método traslada el centro de coordenadas desde su posición por
defecto (0, 0) a la posición indicada.
ctx.translate(x, y);
7.7.2 MÉTODO ROTATE
Éste método inicia la rotación desde su posición por defecto (0,0). Si se
rota el canvas desde esta posición, el contenido podría desaparecer por los
límites del lienzo, por lo que es necesario definir un nuevo origen para la
rotación, dependiendo del resultado deseado.
ctx.rotate(angle);
function draw() {
ctx.translate(75,75);
for (i=1;i<6;i++){
ctx.save();
ctx.fillStyle = 'rgb('+(51*i)+','+(255-51*i)+',255)';
for (j=0;j<i*6;j++){
ctx.rotate(Math.PI*2/(i*6));
ctx.beginPath();
ctx.arc(0,i*12.5,5,0,Math.PI*2,true);
ctx.fill();
ctx.restore();
7.7.3 MÉTODO SCALE
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.
ctx.scale(x, y);
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.
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.
3. Dibujar formas animadas: representación del marco.
4. Restaurar el estado de canvas: restaurar el estado antes de dibujar un
nuevo marco.
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 setInterval y setTimeout, que se
pueden utilizar para llamar a una función específica durante un período
determinado de tiempo.
Ejercicio 7
Ver enunciado
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:
Nota
void clear();
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.setItem('twitter', '@starkyhach');
sessionStorage.setItem('total', 120);
function calcularCosteEnvio(envio) {
alert(calcularCosteEnvio(25));
sessionStorage.setItem('twitter', '@starkyhach');
sessionStorage.setItem('flickr', 'starky.hach');
sessionStorage.removeItem('twitter');
sessionStorage.clear();
var videoDetails = {
title : 'Matrix',
rating: '-2'
};
sessionStorage.setItem('videoDetails',
JSON.stringify(videoDetails) );
var videoDetails =
JSON.parse(sessionStorage.getItem('videoDetails');
StorageEvent {
};
function handleStorage(event) {
// Do somthing
} else {
// Do somthing else
window.attachEvent('storage', handleStorage);
Ejercicio 8
Ver enunciado
});
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 (tx) {
}, function (err) {
alert(err.message);
});
Su sintaxis es la siguiente:
db.transaction(function (tx) {
});
Donde:
1. sqlStatement: 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.
db.transaction(function (tx) {
alert(results.rows.item(i).text);
},
alert(error.message);
);
});
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.transaction(function (tx) {
});
function getTweets() {
$.each(tweets, function(tweet) {
db.transaction(function (tx) {
});
});
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.
db.transaction(function (tx) {
function(tx, results) {
html.push('<li>' +
results.rows.item(i).text + '</li>');
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):
id:21992,
if ('webkitIndexedDB' in window) {
window.IDBTransaction = window.webkitIDBTransaction;
window.IDBKeyRange = window.webkitIDBKeyRange;
request.onerror = function () {
};
};
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:
var db = null;
db = event.target.result;
};
};
db = event.target.result;
if (version != db.version) {
};
verRequest.onerror = function () {
};
};
keyPath: 'title',
autoIncrement: false
});
};
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 createObjectStore admite dos parámetros:
rating: 10,
cover: "/images/wobble.jpg"
rating: 10,
cover: "/images/wobble.jpg"
};
var myIDBTransaction =
window.IDBTransaction
|| window.webkitIDBTransaction
|| { READ_WRITE: 'readwrite' };
var transaction =
db.transaction(['blockbusters'], myIDBTransaction.READ_WRITE);
Analizemos las tres últimas líneas, utilizadas para añadir un nuevo objeto al
almacén:
var myIDBTransaction =
window.IDBTransaction
|| window.webkitIDBTransaction
|| { READ: 'read' };
var transaction =
db.transaction(['blockbusters'], myIDBTransaction.READ);
** Nota **
var transaction =
db.transaction(['blockbusters'], myIDBTransaction.READ);
if (cursor) {
data.push(cursor.value);
cursor.continue();
} else {
};
var myIDBTransaction =
window.IDBTransaction
|| window.webkitIDBTransaction
|| { READ_WRITE: 'readwrite' };
var transaction =
db.transaction(['blockbusters'], myIDBTransaction.READ_WRITE);
Ejercicio 10
Ver enunciado
CAPÍTULO 10 DRAG AND DROP
Durante años, hemos utilizado bibliotecas como jQuery 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.
if (Modernizr.draganddrop) {
} else {
</div>
[draggable] {
user-select: none;
.column:hover {
background-color: #ccc;
border-radius: 10px;
cursor: move;
function handleDragStart(e) {
this.style.opacity = '0.4';
[].forEach.call(cols, function(col) {
});
.column.over {
function handleDragStart(e) {
this.style.opacity = '0.4';
function handleDragOver(e) {
if (e.preventDefault) {
e.dataTransfer.dropEffect = 'move';
return false;
function handleDragEnter(e) {
this.classList.add('over');
function handleDragLeave(e) {
[].forEach.call(cols, function(col) {
});
function handleDrop(e) {
if (e.stopPropagation) {
return false;
}
function handleDragEnd(e) {
col.classList.remove('over');
});
[].forEach.call(cols, function(col) {
});
function handleDragStart(e) {
this.style.opacity = '0.4';
dragSrcEl = this;
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', this.innerHTML);
function handleDrop(e) {
if (e.stopPropagation) {
if (dragSrcEl != this) {
dragSrcEl.innerHTML = this.innerHTML;
this.innerHTML = e.dataTransfer.getData('text/html');
return false;
function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
Ejercicio 12
Ver enunciado
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:
Vía IP: todo dispositivo que se encuentra conectado a la red, tiene asignada
una dirección IP (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.
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.
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.
if(Modernizr.geolocation) {
} else {
navigator.geolocation.getCurrentPosition(function (position) {
});
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
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 null.
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.
navigator.geolocation.watchPosition(function (geodata) {
}, function () {
},
{ enableHighAccuracy: true }
);
PERMISSION_DENIED (valor = 1)
POSITION_UNAVAILABLE (valor = 2)
TIMEOUT (valor = 3)
navigator.geolocation.getCurrentPosition(success, error, {
enableHighAccuracy: true
timeout: 2000
maximumAge: 0
});
Ejercicio 13
Ver enunciado
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.
doWork.js (el Worker):
self.addEventListener('message', function(e) {
self.postMessage(e.data);
}, false);
<output id="result"></output>
<script>
function sayHI() {
function stop() {
function unknownCmd() {
worker.addEventListener('message', function(e) {
document.getElementById('result').textContent = e.data;
}, false);
</script>
doWork.js:
this.addEventListener('message', function(e) {
switch (data.cmd) {
case 'start':
break;
case 'stop':
break;
default:
};
}, false);
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.
if(Modernizr.webworkers) {
} else {
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.
worker.postMessage('Hello World');
worker.addEventListener('message', function(e) {
alert(e.data);
}, false);
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!");
});
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.
pendingWorkers = data.length;
worker.postMessage(JSON.stringify(data[i]));
worker.onmessage = storeResult;
function storeResult(event) {
pendingWorkers--;
if (pendingWorkers <= 0) {
postMessage(JSON.stringify(results));
<output id="result"></output>
<script>
function onError(e) {
document.getElementById('error').textContent = [
function onMsg(e) {
document.getElementById('result').textContent = e.data;
</script>
workerWithError.js:
self.addEventListener('message', function(e) {
};
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
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.
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.
socket.onmessage = function(event) {
if (data.action == 'joined') {
initiliseChat();
} else {
showNewMessage(data.who, data.text);
}
});
Ejercicio 15
Ver enunciado
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:
Un sencillo ejemplo:
es.onopen = function () {
initialiseData();
};
updateData(data.time, data.bid);
};
'Cache-Control': 'no-cache'});
if (lastId) {
connections.push(res);
connections.forEach(function (response) {
history[++eventId] = { agent: req.headers['user-agent'],
});
}).listen(1337, '127.0.0.1');
};
} else {
}
15.2 ACCESO A TRAVÉS DEL FORMULARIO
La forma más sencilla de cargar un archivo es utilizar un elemento <input
type="file"> estándar de formulario. JavaScript devuelve la lista de
objetos File seleccionados como un objeto FileList.
<output id="list"></output>
function handleFileSelect(e) {
f.lastModifiedDate.toLocaleDateString(),
'</li>');
<output id="list"></output>
function handleFileSelect(evt) {
if (!f.type.match('image.*')) {
continue;
return function(e) {
// Render thumbnail.
'" title="',
escape(theFile.name), '"/>'].join('');
list.insertBefore(span, null);
};
})(f);
reader.readAsDataURL(f);
if (!files.length) {
return;
}
var start = 0;
reader.onloadend = function(e) {
document.getElementById('byte_content').textContent =
e.target.result;
document.getElementById('byte_range').textContent =
};
if (file.webkitSlice) {
} else if (file.mozSlice) {
reader.readAsBinaryString(blob);
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.
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.
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 PUSHSTATE()
Supongamos que estamos
visitando http://www.arkaitzgarro.com/html5/index.html y a través de
un script realizamos la siguiente operación:
La nueva URL puede ser cualquier URL dentro del dominio actual. En
cambio, window.location = "#foo" se mantiene siempre en el documento
actual.
No es necesario cambiar la URL actual para añadir una nueva entrada y
almacenar datos asociados.
Podemos asociar datos a una nueva entrada en el historial. Con el enfoque
basado en hash (#), los datos tenemos que añadirlos a la URL.
16.1.2 MÉTODO REPLACESTATE()
El método history.replaceState() 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.
window.onpopstate = function(event) {
};
history.back();
history.back();
history.go(2);
window.onload = function() {
}
CAPÍTULO 17 XMLHTTPREQUEST2
XMLHttpRequest forma parte de las mejoras incrementales que los
creadores de navegadores están implementando a la plataforma base.
xhr.overrideMimeType('text/plain; charset=x-user-defined');
xhr.onreadystatechange = function(e) {
var c = binStr.charCodeAt(i);
};
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.
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
if (this.status == 200) {
...
};
xhr.send();
responseType='blob':
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
img.onload = function(e) {
};
img.src = window.URL.createObjectURL(blob);
document.body.appendChild(img);
...
};
xhr.send();
xhr.responseType = 'text';
xhr.onload = function(e) {
if (this.status == 200) {
console.log(this.response);
};
xhr.send(txt);
sendText2('test string');
Envío de formularios: xhr.send(formdata)
function sendForm() {
formData.append('username', 'johndoe');
formData.append('id', 123456);
xhr.send(formData);
</form>
function sendForm(form) {
formData.append('secret_token', '1234567890');
xhr.send(formData);
formData.append(file.name, file);
xhr.send(formData); // multipart/form-data
document.querySelector('input[type="file"]').addEventListener('cha
nge', function(e) {
uploadFiles('/server', this.files);
}, false);
function upload(blobOrFile) {
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
progressBar.textContent = progressBar.value; //
Fallback for unsupported browsers.
};
xhr.send(blobOrFile);
bb.append('hello world');
upload(bb.getBlob('text/plain'));
function sendArrayBuffer() {
xhr.send(uInt8Array.buffer);
window.requestFileSystem = window.requestFileSystem ||
window.webkitRequestFileSystem;
function onError(e) {
console.log('Error', e);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
fileEntry.createWriter(function(writer) {
bb.append(xhr.response);
writer.write(bb.getBlob('image/png'));
}, onError);
}, onError);
}, onError);
};
xhr.send();
window.BlobBuilder = window.MozBlobBuilder ||
window.WebKitBlobBuilder ||
window.BlobBuilder;
function upload(blobOrFile) {
xhr.send(blobOrFile);
document.querySelector('input[type="file"]').addEventListener('cha
nge', function(e) {
var start = 0;
if ('mozSlice' in blob) {
upload(chunk);
start = end;
}, false);
})();
CAPÍTULO 18 EJERCICIOS
18.1 CAPÍTULO 2
18.1.1 EJERCICIO 1
Dada la siguiente página web, estructurada en XHTML, aplicar las nuevas
etiquetas semánticas de HTML5 donde sea conveniente, manteniendo el
mismo aspecto visual (modificar la hoja de estilos si es necesario) y
funcionalidad. Realizad también los cambios necesarios en la cabecera del
documento (elemento <head>).
18.2 CAPÍTULO 3
18.2.1 EJERCICIO 2
Crear un formulario que contenga lo siguiente:
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):
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:
<ul>
</ul>
18.5 CAPÍTULO 6
18.5.1 EJERCICIO 6
Crear un reproductor de vídeo que cumple las siguientes características:
Reproducir los vídeos independientemente del codec soportado por el
navegador.
Incluir controles de reproducción, pausa, parar, avanzar y retroceder 10
segundos, inicio y fin.
Control de volumen y paso a pantalla completa.
Un indicador de progreso de la reproducción.
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:
18.7 CAPÍTULO 8
18.7.1 EJERCICIO 8
Implementad las siguientes funcionalidades
utilizando SessionStorage y LocalStorage:
Disponer de una tabla para almacenar los tweets. Los campos mínimos son:
identificador del tweet, texto, usuario, y fecha de publicación.
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.
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.
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.
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.
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ó.
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:
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:
Todos los ficheros necesarios para realizar el ejercicio deben ser cacheados,
a excepción del javascript que solicita la petición al servidor.
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.
Si se 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.
function srvTime(url){
xmlHttp.open('HEAD',url,false);
xmlHttp.setRequestHeader("Content-Type", "text/html");
xmlHttp.send(null);
return xmlHttp.getResponseHeader("Date");
var st = srvTime("https://www.google.es/");
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:
18.10 CAPÍTULO 11
18.10.1 EJERCICIO 13
Utilizando los servicios de geolocalización, realizar las siguientes tareas:
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.
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.
type : "color",
type : "history",
type : "message",