En el post anterior hablábamos sobre polyfills y de cómo es posible soportar características que no están disponibles en los navegadores de nuestros usuarios para lograr una experiencia unificada para todos.
En este post examinamos el uso del nuevo API del portapapeles (clipboard API) que facilita mucho el manejo del portapapeles en nuestras aplicaciones. Cabe mencionar que esta es una característica que ya se puede implementar pero tiene la limitante de que únicamente podemos copiar elementos que se encuentran dentro del DOM, y además de forma síncrona. Veamos un ejemplo legacy:
Ejemplo Legacy
Digamos que tenemos un botón y un link
<p>Mandame un mail <a class="js-email" href="mailto:[email protected]">[email protected]</a></p> <p><button class="btn-copy"><img src="./images/copy-icon.png" /></button></p>
Y queremos que cuando el usuario haga click sobre el btn-copy el email del link se copie al portapapeles. Bien, para ello necesitamos el siguiente código javascript:
var copyEmailBtn = document.querySelector('.btn-copy'); copyEmailBtn.addEventListener('click', function(event) { // Seleccionamos el texto dentro de la etiqueta de link var email = document.querySelector('.js-email'); var range = document.createRange(); range.selectNode(email); window.getSelection().addRange(range); try { // Ahora que el texto ha sido seleccionado ejecutamos el comando para copiar var exito = document.execCommand('copy'); var mensaje = exito ? 'exito' : 'fracaso'; console.log('El comando para copiar el email fue un: ' + mensaje); } catch(err) { console.log('Caracoles! algo ha salido mal'); } // quitamos la seleccion del texto :) window.getSelection().removeAllRanges(); });
Ejemplo Con El Nuevo API
El nuevo clipboard API, nos ofrece muchas características muy cómodas para usar el portapapeles, entre otras la capacidad de leer/escribir del portapapeles aun cuando los elementos en el portapapeles no se encuentren en el DOM de la aplicación.
Para copiar un texto al portapapeles necesitamos hacer lo siguiente:
navigator.clipboard.writeText('El texto que vamos a copiar') .then(() => { console.log('Texto copiado'); }) .catch(err => { // Esto pasa si el usuario no nos dio permiso para usar su portapapeles :C console.error('No pudimos escribir en el portapapeles: ', err); });
Como este API es asíncrono podemos hacerlo también en forma de una función async/await
async function copiarUrlActual() { try { await navigator.clipboard.writeText(location.href); console.log('URL Copiada'); } catch (err) { console.error('No pudimos copiar: ', err); } }
De forma análoga podemos leer (pegar) los contenidos del portapapeles:
navigator.clipboard.readText() .then(text => { console.log('Pegado: ', text); }) .catch(err => { console.error('Fallamos!: ', err); });
Y de forma similar la funcion asincrona:
async function leerPortapapeles() { try { const text = await navigator.clipboard.readText(); console.log('Pegado: ', text); } catch (err) { console.error('Fallamos!: ', err); } }
Eventos
Con el nuevo clipboard API también podemos capturar eventos, es decir reaccionar cada vez que los usuarios pegan algo en nuestra aplicación desde su portapapeles.
document.addEventListener('paste', evento => { evento.preventDefault(); navigator.clipboard.readText().then(texto => { console.log('Texto pegado: ', texto); }); });
Seguridad
Pero claro, que no era seguro ir por ahí leyendo los links que nuestros alegres usuarios esconden en su portapapeles…
Por eso primero que nada debemos pedirles permiso, usando el permission API iniciamos un diálogo en el que pedimos permiso para que nos dejen ver su portapapeles, al concedernos las siguientes capacidades en su navegador:
{ name: 'clipboard-read' } { name: 'clipboard-write' }
Para pedir permiso al usuario es necesario el siguiente código:
navigator.permissions.query({ name: 'clipboard-read' }).then(permisoStatus => { // el status puede serpuede ser: 'granted', 'denied' o 'prompt': console.log(permisoStatus.state); // Escuchamos cuando los permisos cambien permisoStatus.onchange = () => { console.log(permisoStatus.state); }; });
recuerden, como todo es asíncrono pueden usar promesas, o bien async/await. Cada status del proceso se puede describir así:
- granted: El permiso fue concedido
- denied: El permiso fue denegado
- promt: Estamos pidiendo permiso (está en proceso)
Conclusión
Manejar el portapapeles se ha vuelto más fácil, más versátil y más seguro. Recuerden que este feature estará disponible a partir de las siguientes versiones de los navegadores más conocidos:
- Chrome: Version 66