Abbattere le barriere con l'API DataTransfer

Consente all'utente di condividere dati al di fuori della finestra del browser.

Potresti aver sentito parlare dell'API DataTransfer, che fa parte dell'API HTML5 Drag and Drop e degli eventi della clipboard. Può essere utilizzato per trasferire dati tra l'origine e i target di ricezione.

Supporto dei browser

  • Chrome: 3.
  • Edge: 12.
  • Firefox: 3.5.
  • Safari: 4.

Origine

Le interazioni di trascinamento e copia e incolla vengono spesso utilizzate per le interazioni all'interno di una pagina per trasferire testo semplice da A a B. Tuttavia, spesso viene trascurata la possibilità di utilizzare queste stesse interazioni per andare oltre la finestra del browser.

Sia le interazioni di trascinamento e rilascio integrate del browser sia quelle di copia e incolla possono comunicare con altre applicazioni, web o di altro tipo, e non sono legate a nessuna origine. L'API supporta più voci di dati con comportamenti diversi in base a dove vengono trasferiti i dati. La tua applicazione web può inviare e ricevere i dati trasferiti quando ascolta gli eventi in arrivo.

Questa funzionalità può cambiare il nostro modo di concepire la condivisione e l'interoperabilità nelle applicazioni web su computer. Il trasferimento dei dati tra le applicazioni non deve più basarsi su integrazioni fortemente accoppiate. In alternativa, puoi dare agli utenti il controllo completo per trasferire i dati dove vogliono.

Un esempio di interazioni possibili con l'API DataTransfer. (Il video non include l'audio).

Trasferimento di dati

Per iniziare, devi implementare il trascinamento o il copia e incolla. Gli esempi riportati di seguito mostrano le interazioni con il trascinamento, ma la procedura per la copia e incolla è simile. Se non hai dimestichezza con l'API Drag and Drop, consulta questo ottimo articolo che spiega il trascinamento HTML5, che illustra tutti i dettagli.

Fornendo dati con chiave MIME-type, puoi interagire liberamente con le applicazioni esterne. La maggior parte degli editor WYSIWYG, degli editor di testo e dei browser risponde ai tipi MIME "primitivi" utilizzati nell'esempio riportato di seguito.

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');
});

Nota la proprietà event.dataTransfer. Viene restituita un'istanza di DataTransfer. Come vedrai, a volte questo oggetto viene restituito da proprietà con altri nomi.

La ricezione del trasferimento dei dati funziona quasi come la relativa impostazione. Ascolta gli eventi di ricezione (drop o paste) e leggi le chiavi. Quando trascini un elemento, il browser ha accesso solo alle chiavi type dei dati. È possibile accedere ai dati stessi solo dopo un calo.

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();
});

Tre tipi MIME sono ampiamente supportati nelle applicazioni:

  • text/html: esegue il rendering del payload HTML negli elementi contentEditable e negli editor di testo avanzato (WYSIWYG) come Documenti Google, Microsoft Word e altri.
  • text/plain: Imposta il valore degli elementi di input, dei contenuti degli editor di codice e della creatività di riserva da text/html.
  • text/uri-list: consente di passare all'URL quando lo inserisci nella barra degli URL o nella pagina del browser. Quando rilasci un file in una directory o sul desktop, viene creata una scorciatoia per l'URL.

L'adozione diffusa di text/html da parte degli editor WYSIWYG lo rende molto utile. Come nei documenti HTML, puoi incorporare le risorse utilizzando URL di dati o URL accessibili pubblicamente. Questo metodo funziona bene con l'esportazione di elementi visivi (ad esempio da una tela) in editor come Documenti Google.

const redPixel = 'data:image/gif;base64,R0lGODdhAQABAPAAAP8AAAAAACwAAAAAAQABAAACAkQBADs=';
const html = '<img src="' + redPixel + '" width="100" height="100" alt="" />';
event.dataTransfer.setData('text/html', html);

Trasferimento tramite copia e incolla

Di seguito è riportato un esempio di utilizzo dell'API DataTransfer con le interazioni di copia e incolla. Tieni presente che l'oggetto DataTransfer viene restituito da una proprietà chiamata clipboardData per gli eventi della clipboard.

// 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);
  }
});

Formati di dati personalizzati

Non sei limitato ai tipi MIME primitivi, ma puoi utilizzare qualsiasi chiave per identificare i dati trasferiti. Questo può essere utile per le interazioni tra browser all'interno dell'applicazione. Come mostrato di seguito, puoi trasferire dati più complessi utilizzando le funzioni JSON.stringify() e 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);
  }
});

Connessione al web

Sebbene i formati personalizzati siano ideali per la comunicazione tra le applicazioni che hai sotto controllo, limita anche l'utente durante il trasferimento dei dati ad applicazioni che non utilizzano il tuo formato. Se vuoi collegarti ad applicazioni di terze parti sul web, hai bisogno di un formato di dati universale.

Lo standard JSON-LD (Linked Data) è un'ottima soluzione. È leggero e facile da leggere e scrivere in JavaScript. Schema.org contiene molti tipi predefiniti che possono essere utilizzati e sono disponibili anche definizioni di schema personalizzate.

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));

Quando utilizzi i tipi di Schema.org, puoi iniziare con il tipo generico Thing oppure utilizzare qualcosa di più vicino al tuo caso d'uso, come Event, Person, MediaObject, Place o, se necessario, tipi molto specifici come MedicalEntity. Quando utilizzi TypeScript, puoi utilizzare le definizioni di interfaccia dalle definizioni di tipo schema-dts.

Trasmettendo e ricevendo dati JSON-LD, sosterrai un web più connesso e aperto. Con le applicazioni che parlano la stessa lingua, puoi creare integrazioni approfondite con applicazioni esterne. Non sono necessarie complesse integrazioni API; tutte le informazioni necessarie sono incluse nei dati trasferiti.

Pensa a tutte le possibilità di trasferimento dei dati tra qualsiasi applicazione (web) senza limitazioni: condivisione di eventi da un calendario alla tua app ToDo preferita, allegazione di file virtuali alle email, condivisione di contatti. Sarebbe fantastico, giusto? Tutto parte da te. 🙌

Problemi

Sebbene l'API DataTransfer sia già disponibile, ci sono alcune cose da tenere presenti prima dell'integrazione.

Compatibilità del browser

I browser desktop supportano tutti molto bene la tecnica descritta sopra, mentre i dispositivi mobili no. La tecnica è stata testata su tutti i principali browser (Chrome, Edge, Firefox, Safari) e sistemi operativi (Android, ChromeOS, iOS, macOS, Ubuntu Linux e Windows), ma purtroppo Android e iOS non hanno superato il test. Mentre i browser continuano a svilupparsi, per il momento la tecnica è limitata solo ai browser desktop.

Visibilità

Il trascinamento e il copia e incolla sono interazioni a livello di sistema quando si lavora su un computer, con origini che risalgono alle prime GUI di oltre 40 anni fa. Pensa a quante volte hai utilizzato queste interazioni per organizzare i file. Questo non è ancora molto comune sul web.

Dovrai informare gli utenti di questa nuova interazione e creare pattern di UX per renderla riconoscibile, in particolare per le persone la cui esperienza con i computer finora è stata limitata ai dispositivi mobili.

Accessibilità

Il trascinamento non è un'interazione molto accessibile, ma l'API DataTransfer funziona anche con il copia e incolla. Assicurati di ascoltare gli eventi di copia e incolla. Non richiede molto lavoro aggiuntivo e i tuoi utenti ti ringrazieranno per averlo aggiunto.

Sicurezza e privacy

Quando utilizzi questa tecnica, devi tenere conto di alcune considerazioni relative alla sicurezza e alla privacy.

  • I dati del portachiavi sono disponibili per altre applicazioni sul dispositivo dell'utente.
  • Le applicazioni web che stai trascinando hanno accesso alle chiavi di tipo, non ai dati. I dati diventano disponibili solo al rilascio o al trascinamento.
  • I dati ricevuti devono essere trattati come qualsiasi altro input utente; sottoponili a sanificazione e convalida prima dell'utilizzo.

Iniziare a utilizzare la libreria di assistenza Transmat

Ti entusiasma l'idea di utilizzare l'API DataTransfer nella tua applicazione? Ti consigliamo di dare un'occhiata alla libreria Transmat su GitHub. Questa libreria open source allinea le differenze tra i browser, fornisce utilità JSON-LD, contiene un osservatore per rispondere agli eventi di trasferimento per evidenziare le aree di rilascio e consente di integrare le operazioni di trasferimento dei dati tra le implementazioni esistenti del trascinamento.

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);

Ringraziamenti

Immagine hero di Luba Ertel su Unsplash.