El tema de las esquinas redondeadas es algo bastante frecuente en los sitios de desarrollo web, pero antes no habÃa visto ninguno que lo hiciera usando Canvas.
El script del que hablamos añade varios efectos a nuestras imágenes de forma no obtrusiva, usando para ello canvas. Navegadores como Mozilla Firefox 1.5+, Opera 9+ y Safari mostrarán los efectos indicados, mientras que navegadores antiguos y el Internet Explorer no mostrarán nada.
Para incluir los efectos se debe modificar el class y añadir diversos tipos para cada efecto y asà poder hacer combinaciones. Entre los efectos nos encontramos: esquinas redondeadas, efecto shading (con transparencia configurable) y sombras. Corner.js
VÃa / dzone
Un efecto llamativo que se suele hacer con Flash es realizar una transición entre dos imágenes cuando se posiciona sobre ella.
El efecto es sencillo, disponemos de una cabecera (H1) en el que hay un elemento con posicionamiento absoluto y que contiene la imagen final, y un enlace (el que se suele usar para ir al home) que tiene la imagen original mediante estilos.
El proceso es el siguiente: cuando se posiciona el ratón sobre el enlace se crea efecto fadeout y cuando se sale se crea el efecto fadein. Ambos efectos se hacen con tiempo de retardo para dar continuidad.
Todo el código en el post original. Creating a fading header
Vía / CSS Globe
A simple jQuery plugin to get albums and images from Picasa without the need for PHP, Ruby, or any other server side language. Makes it easy to create a simple, dynamic, free, client-side-only image gallery. …
Facebook pone a disposición de sus usuarios unos sliders para poder controlar el valor de ciertos elementos. Para aquellos que estén interesados en usarlos, podrán echar mano de este ejemplo realizado con Mootools, cuyo uso es muy sencillo.
Hay que tener en cuenta que no es un script accesible, porque no existe una alternativa estándar al control, ya que el slider es una capa y si no hay javascript o entorno gráfico, el valor no se podría cambiar. El script es bueno y añadirle la parte de accesibilidad no implica mucha complicación. Facebook Sliders With Mootools and CSS
Vía / CSS Globe
Hoy toca realizar conexiones con el servidor usando llamadas autenticadas. Para eso usaremos JWT (JSON Web Token), que viene a ser el envío de un token en cada llamada que necesita autenticación. El token está formado por tres cadenas codificadas en base64 y separadas por un punto (header.payload.signature). En el payload se envía toda la info que queramos, pero sin pasarse porque el token no debería ser muy largo y sobre todo sin enviar información sensible, porque el token no está encriptado, es por ello que la comunicación navegador/servidor debe ser mediante HTTPS. Si quieres una explicación más detallada, aquí te lo explican mejor.
En el payload vamos a guardar varios claims, entre ellos el username y un uuid que usaremos para validar que el usuario es correcto. JWT asegura que el token es válido, pero no viene mal añadir cierta seguridad. Cuando el usuario se loguea un nuevo uuid es generado, por lo que se comprobará si coinciden para el username enviado.
Ya tenemos la explicación teórica, ahora vamos con la parte de programación, primero la parte servidor y luego el frontend.
Lo primero que tenemos que hacer es añadir un nuevo plugin a hapi.js que se encargue de la autenticación, registrando un nuevo strategy a server.auth que use JWT. El plugin hapi-auth-jwt2 se encargará de toda la autenticación JWT y añadiremos una capa extra de validación comprobando que el username y el uuid coinciden.
Y por último añadimos una nueva ruta para autenticar (login) el usuario, comprobamos que el usuario y la contraseña coinciden, y si es así, creamos un uuid que guardamos en la bd y generamos el JWT y lo enviamos en la cabecera Authorization:
Vale, ya tenemos la parte del servidor, ahora la parte del frontend. Primero es añadir las rutas para /login, /account y /logout. He añadido un meta que indica si la ruta tiene que ser obligatoriamente autenticada, obligatoriamente no autenticada o como sea. Para ello, para cada ruta comprobará si el JWT token está almacenado o no y según el meta redirigirá a home o continuará:
Para gestionar el almacenamiento en el navegador en vez de cookies vamos a usar sessionStorage y localStorage para guardar el token JWT. Como el formulario de login permite recordar la sesión, vamos a usar ambos storages. Si no se recuerda usaremos sessionStorage, que se borrará cuando se cierra el navegador, en caso contrario usaremos localStorage.
import Config from'@/js/config';
/**
* API methods for sesion/local storage.
* Depending on `this.session` it saves only on `sessionStorage` or also in `localStorage`
*
* @since v0.8.0
*/classstorage{
/**
* Constructor
*
* @param {boolean} session If stored only in session
*/constructor( session = false ) {
this.session = session;
}
/**
* It saves the token in the session (and local storage is this.session === false),
*
* @param {strig} token JWT token
*/
setJWTToken( token ) {
sessionStorage.setItem( Config.jwt.storageKey, token );
if ( ! this.session ) {
localStorage.setItem( Config.jwt.storageKey, token );
}
}
/**
* It gets a value from session storage or in local if session = false
*
* @returns {string}
*/
getJWTToken() {
const sessionValue = sessionStorage.getItem( Config.jwt.storageKey );
if ( sessionValue ) {
return sessionValue;
}
if ( ! this.session ) {
const storedValue = localStorage.getItem( Config.jwt.storageKey );
return storedValue;
}
returnnull;
}
/**
* Removes JWT token from session and local storage
*/
removeJWTToken() {
sessionStorage.removeItem( Config.jwt.storageKey );
localStorage.removeItem( Config.jwt.storageKey );
}
}
exportdefault storage;
También hemos creado una librería para tratar las llamadas a la API. Hay dos métodos, uno para autenticar el usuario (login) que mirará la cabecera Authorization, y otro método que obtiene los datos del usuario actual realizando una llamada autenticada enviando el JWT token en la cabecera Authorization:
import Config from'@/js/config';
import Storage from'@/js/utils/storage';
/**
* API backend methods
*
* @since 0.8.0
*/classapiFetch{
/**
* Authenticate an user, if ok, JWT token is sent by the server in Authorization header
*
* @param {string} username User name
* @param {string} password Password
*
* @returns {Promise}
*/
auth( username, password ) {
return fetch( Config.api.user.auth, {
method: 'POST',
body: JSON.stringify(
{ username, password }
),
mode: 'cors',
} ).then( response => {
const auth = response.headers.get( 'Authorization' );
if ( auth ) {
return {
response: true,
token: auth,
};
}
return {
response: false,
message: 'Username or password not valid',
};
} );
}
getUser( username ) {
return fetch( `${ Config.api.user.get }${ username }`, {
method: 'GET',
headers: {
Authorization: new Storage().getJWTToken(),
},
} ).then( response => response.json() );
}
}
exportdefault apiFetch;
Ahora solo faltan los controladores para login, account y logout. Login realizar la llamada al servidor y si se obtiene el JWT se guarda:
<template><sectionclass="section"><divclass="container"><h1class="title">
Login
</h1><divv-if="error"class="columns is-centered has-margin-bottom-2"
><b-notificationclass="column is-7-tablet is-6-desktop is-5-widescreen"type="is-danger"has-iconaria-close-label="Close notification"role="alert"size="is-small "
>
{{ error }}
</b-notification></div></div><divclass="container"><divclass="columns is-centered"><divclass="column is-5-tablet is-4-desktop is-3-widescreen has-background-light login-form"><b-fieldlabel="Username"><b-inputv-model="username"value=""maxlength="30"icon="account-circle-outline"
/></b-field><b-fieldlabel="Password"><b-inputv-model="password"value=""type="password"icon="lock-outline"
/></b-field><divclass="field"><b-checkboxv-model="remember">
Remember me
</b-checkbox></div><divclass="has-text-right"><b-buttontype="is-primary"
@click="submit"
>
Log in
</b-button></div></div></div></div></section></template><script>import ApiFectch from'@/js/utils/api';
import Storage from'@/js/utils/storage';
exportdefault {
name: 'Login',
// Form data and error messages if login fails
data() {
return {
username: '',
password: '',
remember: false,
error: '',
};
},
methods: {
// It logs in, using the backend API for authenticate the user data.// If user logs in, it saves the JWT token in the browser. If not, shows error message.
submit: function() {
const api = new ApiFectch();
api.auth( this.username, this.password )
.then( response => {
const storage = new Storage( ! this.remember );
if ( !! response.response && !! response.token ) {
storage.setJWTToken( response.token );
this.error = false;
// `go` refreshes the page, so user data is updatedthis.$router.go( '/' );
} else {
storage.removeJWTToken();
this.error = response.message;
}
} );
},
},
};
</script><stylelang="scss"scoped>.login-form {
border-radius: 4px;
}
</style>
Logout borra los datos JWT del navegador y redirige a home:
<template><sectionclass="hero is-medium is-primary is-bold"><divclass="hero-body"><divclass="container has-text-centered"><h1class="title">
{{ message }}
</h1><h2class="subtitle">
Miss you 💛
</h2></div></div></section></template><script>import User from'@/js/utils/user';
exportdefault {
name: 'Logout',
// Dummy data
data() {
return {
message: 'Bye',
};
},
// After being created it logs out and go to home
created() {
new User().logout();
// `go` instead of `push` because refreshing the page updates the user data// Maybe using vuex is a better way to do it, or not...this.$router.go( '/' );
},
};
</script>
Y Account recupera los datos del usuario una vez que ha creado el controlador:
<template><divid="account"><sectionclass="hero is-primary is-bold"><divclass="hero-body"><divclass="has-text-centered"><h1class="title">
{{ message }}
</h1><h2class="subtitle">
Your data
</h2></div></div></section><sectionclass="section"><divclass="container"><divclass="tile is-ancestor"><divclass="tile is-parent"><pclass="tile is-child notification">
Some content
</p></div><divclass="tile is-8 is-parent"><divclass="tile is-child notification is-info"><ulid="data"><liv-for="( value, key ) in user":key="key"
>
{{ key }} : {{ value }}
</li></ul></div></div></div></div></section></div></template><script>// Dummy componentimport ApiFectch from'@/js/utils/api';
import User from'@/js/utils/user';
exportdefault {
name: 'Account',
data() {
return {
message: 'Account',
user: {},
};
},
created() {
const user = new User().getCurrentUser();
new ApiFectch().getUser( user.username )
.then( response =>this.user = response );
},
};
</script>
Interesante plugin para jQuery que permite retrasar la carga de imágenes para que la carga de la página sea más rápida. Para ello, cargará las imágenes sólo cuando se vean mediante el scroll. Un script que está pensado para páginas con gran número de imágenes pesadas.