Permite que el usuario comparta datos más allá de la ventana del navegador.
Es posible que hayas escuchado sobre la API de DataTransfer, que forma parte de la API de arrastrar y soltar de HTML5 y los eventos del portapapeles. Se puede usar para transferir datos entre los destinos de origen y de recepción.
Las interacciones de arrastrar y soltar y copiar y pegar suelen usarse para interacciones dentro de una página para transferir texto simple de A a B. Pero lo que a menudo se pasa por alto es la capacidad de usar esas mismas interacciones para ir más allá de la ventana del navegador.
Tanto la función de arrastrar y soltar integrada en el navegador como las interacciones de copiar y pegar pueden comunicarse con otras aplicaciones, ya sean web o de otro tipo, y no están vinculadas a ningún origen. La API admite varias entradas de datos con diferentes comportamientos según el lugar al que se transfieren los datos. Tu aplicación web puede enviar y recibir los datos transferidos cuando escucha eventos entrantes.
Esta función puede cambiar la forma en que pensamos en el uso compartido y la interoperabilidad en las aplicaciones web para computadoras de escritorio. La transferencia de datos entre aplicaciones ya no necesita depender de integraciones estrechamente vinculadas. En su lugar, puedes darles a los usuarios el control total para transferir datos a donde quieran.
Cómo transferir datos
Para comenzar, deberás implementar la función de arrastrar y soltar o copiar y pegar. En los siguientes ejemplos, se muestran interacciones de arrastrar y soltar, pero el proceso de copiar y pegar es similar. Si no conoces la API de arrastrar y soltar, puedes consultar un excelente artículo en el que se explica cómo arrastrar y soltar HTML5, en el que se explican los pros y los contras.
Cuando proporcionas datos con clave de tipo MIME, puedes interactuar libremente con aplicaciones externas. La mayoría de los editores, editores de texto y navegadores WYSIWYG responden a los tipos de MIME "primitivos" que se usan en el siguiente ejemplo.
document.querySelector('#dragSource')
.addEventListener('dragstart', (event) => {
event.dataTransfer.setData('text/plain', 'Foo bar');
event.dataTransfer.setData('text/html', '<h1>Foo bar</h1>');
event.dataTransfer.setData('text/uri-list', 'https://example.com');
});
Observa la propiedad event.dataTransfer
. Esto muestra una instancia de DataTransfer
. Como verás, a veces las propiedades devuelven este objeto con otros nombres.
Recibir la transferencia de datos funciona casi igual que proporcionarla. Escucha los eventos de recepción (drop
o paste
) y lee las claves. Cuando se arrastra sobre un elemento, el navegador solo tiene acceso a las claves type
de los datos. Solo se puede acceder a los datos después de una publicación.
document.querySelector('#dropTarget')
.addEventListener('dragover', (event) => {
console.log(event.dataTransfer.types);
// Without this, the drop event won't fire.
event.preventDefault();
});
document.querySelector('#dropTarget')
.addEventListener('drop', (event) => {
// Log all the transferred data items to the console.
for (let type of event.dataTransfer.types) {
console.log({ type, data: event.dataTransfer.getData(type) });
}
event.preventDefault();
});
Hay tres tipos de MIME ampliamente admitidos en todas las aplicaciones:
text/html
: Renderiza la carga útil HTML en elementoscontentEditable
y editores de texto enriquecido (WYSIWYG), como Documentos de Google, Microsoft Word y otros.text/plain:
Establece el valor de los elementos de entrada, el contenido de los editores de código y el resguardo detext/html
.text/uri-list
: Navega a la URL cuando se coloca en la barra de URL o en la página del navegador. Se creará un acceso directo de URL cuando se acceda a un directorio o al escritorio.
La adopción generalizada de text/html
por los editores WYSIWYG la hace muy útil. Al igual que en los documentos HTML, puedes incorporar recursos mediante URLs de datos o URL de acceso público. Esto funciona bien con la exportación de imágenes (por ejemplo, desde un lienzo) a editores como Documentos de Google.
const redPixel = 'data:image/gif;base64,R0lGODdhAQABAPAAAP8AAAAAACwAAAAAAQABAAACAkQBADs=';
const html = '<img src="' + redPixel + '" width="100" height="100" alt="" />';
event.dataTransfer.setData('text/html', html);
Cómo transferir con la función de copiar y pegar
A continuación, se muestra el uso de la API de DataTransfer con interacciones de copiar y pegar. Ten en cuenta que una propiedad llamada clipboardData
muestra el objeto DataTransfer
para los eventos del portapapeles.
// Listen to copy-paste events on the document.
document.addEventListener('copy', (event) => {
const copySource = document.querySelector('#copySource');
// Only copy when the `activeElement` (i.e., focused element) is,
// or is within, the `copySource` element.
if (copySource.contains(document.activeElement)) {
event.clipboardData.setData('text/plain', 'Foo bar');
event.preventDefault();
}
});
document.addEventListener('paste', (event) => {
const pasteTarget = document.querySelector('#pasteTarget');
if (pasteTarget.contains(document.activeElement)) {
const data = event.clipboardData.getData('text/plain');
console.log(data);
}
});
Formatos de datos personalizados
No estás limitado a los tipos de MIME primitivos, pero puedes usar cualquier clave para identificar los datos transferidos. Esto puede ser útil para las interacciones entre navegadores en tu aplicación. Como se muestra a continuación, puedes transferir datos más complejos con las funciones JSON.stringify()
y JSON.parse()
.
document.querySelector('#dragSource')
.addEventListener('dragstart', (event) => {
const data = { foo: 'bar' };
event.dataTransfer.setData('my-custom-type', JSON.stringify(data));
});
document.querySelector('#dropTarget')
.addEventListener('dragover', (event) => {
// Only allow dropping when our custom data is available.
if (event.dataTransfer.types.includes('my-custom-type')) {
event.preventDefault();
}
});
document.querySelector('#dropTarget')
.addEventListener('drop', (event) => {
if (event.dataTransfer.types.includes('my-custom-type')) {
event.preventDefault();
const dataString = event.dataTransfer.getData('my-custom-type');
const data = JSON.parse(dataString);
console.log(data);
}
});
Conexión a la Web
Si bien los formatos personalizados son ideales para la comunicación entre aplicaciones que tienes bajo tu control, también limitan al usuario cuando se transfieren datos a aplicaciones que no usan tu formato. Si quieres conectarte con aplicaciones de terceros en la Web, necesitas un formato de datos universal.
El estándar JSON-LD (datos vinculados) es un gran candidato para esto. Es ligero y fácil de leer y escribir en JavaScript. Schema.org contiene muchos tipos predefinidos que se pueden usar, y las definiciones de esquemas personalizados también son una opción.
const data = {
'@context': 'https://schema.org',
'@type': 'ImageObject',
contentLocation: 'Venice, Italy',
contentUrl: 'venice.jpg',
datePublished: '2010-08-08',
description: 'I took this picture during our honey moon.',
name: 'Canal in Venice',
};
event.dataTransfer.setData('application/ld+json', JSON.stringify(data));
Cuando uses los tipos de Schema.org, puedes comenzar con el tipo genérico Thing o usar algo más cercano a tu caso de uso, como Event, Person, MediaObject, Place o incluso tipos muy específicos, como MedicalEntity, si es necesario. Cuando usas TypeScript, puedes utilizar las definiciones de interfaz de las definiciones de tipo de schema-dts.
Al transmitir y recibir datos JSON-LD, respaldarás una Web más conectada y abierta. Cuando las aplicaciones hablan el mismo idioma, puedes crear integraciones profundas con aplicaciones externas. No es necesario realizar integraciones de API complicadas; toda la información necesaria se incluye en los datos transferidos.
Piensa en todas las posibilidades de transferir datos entre cualquier aplicación (web) sin restricciones: compartir eventos de un calendario a tu app de tareas pendientes favorita, adjuntar archivos virtuales a correos electrónicos y compartir contactos. Sería genial, ¿verdad? ¡Comienza por ti! 🙌
Problemas
Si bien la API de DataTransfer está disponible en la actualidad, hay algunas cosas que debes tener en cuenta antes de realizar la integración.
Compatibilidad del navegador
Los navegadores para computadoras de escritorio son muy compatibles con la técnica descrita anteriormente, mientras que los dispositivos móviles no lo son. La técnica se probó en todos los navegadores principales (Chrome, Edge, Firefox y Safari) y sistemas operativos (Android, ChromeOS, iOS, macOS, Ubuntu Linux y Windows), pero, lamentablemente, Android y iOS no aprobaron la prueba. Aunque los navegadores continúan desarrollándose, por ahora, la técnica se limita solo a los navegadores de escritorio.
Visibilidad
El arrastrar y soltar y el copiar y pegar son interacciones a nivel del sistema cuando se trabaja en una computadora de escritorio, con orígenes que se remontan a las primeras GUI hace más de 40 años. Piensa en cuántas veces has gebruikt estas interacciones para organizar archivos. Esto aún no es muy común en la Web.
Deberás educar a los usuarios sobre esta nueva interacción y crear patrones de UX para que sea reconocible, en especial para las personas cuya experiencia con las computadoras hasta ahora se limitó a los dispositivos móviles.
Accesibilidad
La interacción de arrastrar y soltar no es muy accesible, pero la API de DataTransfer también funciona con la función de copiar y pegar. Asegúrate de escuchar los eventos de copiar y pegar. No requiere mucho trabajo adicional, y tus usuarios te agradecerán que lo hayas agregado.
Seguridad y privacidad
Hay algunas consideraciones de seguridad y privacidad que debes tener en cuenta al utilizar esta técnica.
- Los datos del portapapeles están disponibles para otras aplicaciones en el dispositivo del usuario.
- Las aplicaciones web que arrastras tienen acceso a las teclas de tipo, no a los datos. Los datos solo están disponibles cuando se sueltan o pegan.
- Los datos recibidos se deben tratar como a cualquier otra entrada del usuario; limpia y valida antes de usarlos.
Comienza a usar la biblioteca de ayuda de Transmat
¿Te entusiasma usar la API de DataTransfer en tu aplicación? Considera consultar la biblioteca de Transmat en GitHub. Esta biblioteca de código abierto alinea las diferencias del navegador, proporciona utilidades de JSON-LD, contiene un observador que responda a los eventos de transferencia para destacar las áreas de la función de soltar, y te permite integrar las operaciones de transferencia de datos entre las implementaciones existentes de arrastrar y soltar.
import { Transmat, TransmatObserver, addListeners } from 'transmat';
// Send data on drag/copy.
addListeners(myElement, 'transmit', (event) => {
const transmat = new Transmat(event);
transmat.setData({
'text/plain': 'Foobar',
'application/json': { foo: 'bar' },
});
});
// Receive data on drop/paste.
addListeners(myElement, 'receive', (event) => {
const transmat = new Transmat(event);
if (transmat.hasType('application/json') && transmat.accept()) {
const data = JSON.parse(transmat.getData('application/json'));
}
});
// Observe transfer events and highlight drop areas.
const obs = new TransmatObserver((entries) => {
for (const entry of entries) {
const transmat = new Transmat(entry.event);
if (transmat.hasMimeType('application/json')) {
entry.target.classList.toggle('drag-over', entry.isTarget);
entry.target.classList.toggle('drag-active', entry.isActive);
}
}
});
obs.observe(myElement);
Agradecimientos
Imagen hero de Luba Ertel en Unsplash.