Surmonter les obstacles avec l'API DataTransfer

Permet à l'utilisateur de partager des données au-delà de la fenêtre du navigateur.

Vous avez peut-être entendu parler de l'API DataTransfer, qui fait partie de l'API HTML5 Drag and Drop et des événements du presse-papiers. Il peut être utilisé pour transférer des données entre des cibles sources et de réception.

Browser Support

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

Source

Les interactions de type glisser-déposer et copier-coller sont souvent utilisées pour les interactions sur une page afin de transférer du texte simple d'un point A à un point B. Cependant, on oublie souvent qu'il est possible d'utiliser ces mêmes interactions pour aller au-delà de la fenêtre du navigateur.

Les interactions de type glisser-déposer et copier-coller intégrées au navigateur peuvent communiquer avec d'autres applications, Web ou non, et ne sont liées à aucune origine. L'API accepte plusieurs entrées de données avec des comportements différents selon l'emplacement où les données sont transférées. Votre application Web peut envoyer et recevoir les données transférées lorsqu'elle écoute les événements entrants.

Cette fonctionnalité peut changer notre façon de penser au partage et à l'interopérabilité dans les applications Web sur ordinateur. Le transfert de données entre les applications ne nécessite plus d'intégrations étroitement couplées. Vous pouvez plutôt donner aux utilisateurs le contrôle total sur le transfert de données vers l'emplacement de leur choix.

Exemple d'interactions possibles avec l'API DataTransfer. (La vidéo n'inclut pas de son.)

Transfert des données

Pour commencer, vous devez implémenter le glisser-déposer ou le copier-coller. Les exemples ci-dessous montrent des interactions de type glisser-déposer, mais le processus de copier-coller est similaire. Si vous ne connaissez pas l'API Drag and Drop, lisez cet excellent article sur le glisser-déposer en HTML5, qui explique tout ce qu'il faut savoir.

En fournissant des données associées à un type MIME, vous pouvez interagir librement avec des applications externes. La plupart des éditeurs WYSIWYG, des éditeurs de texte et des navigateurs répondent aux types MIME "primitifs" utilisés dans l'exemple ci-dessous.

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

Notez la propriété event.dataTransfer. Cela renvoie une instance de DataTransfer. Comme vous le verrez, cet objet est parfois renvoyé par des propriétés portant d'autres noms.

La réception du transfert de données fonctionne presque de la même manière que l'envoi. Écoutez les événements de réception (drop ou paste) et lisez les clés. Lorsque vous faites glisser un élément, le navigateur n'a accès qu'aux clés type des données. Les données elles-mêmes ne sont accessibles qu'après une dépose.

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

Trois types MIME sont largement acceptés dans les applications :

  • text/html : affiche la charge utile HTML dans les éléments contentEditable et les éditeurs de texte enrichi (WYSIWYG) tels que Google Docs, Microsoft Word, etc.
  • text/plain: définit la valeur des éléments d'entrée, le contenu des éditeurs de code et le remplacement de text/html.
  • text/uri-list : accède à l'URL lorsque vous la déposez dans la barre d'adresse ou sur la page du navigateur. Un raccourci URL est créé lorsque vous déposez un fichier sur un répertoire ou sur le bureau.

L'adoption généralisée de text/html par les éditeurs WYSIWYG le rend très utile. Comme dans les documents HTML, vous pouvez intégrer des ressources à l'aide d'URL de données ou d'URL accessibles au public. Cela fonctionne bien pour exporter des éléments visuels (par exemple, à partir d'un canevas) vers des éditeurs tels que Google Docs.

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

Transférer des données à l'aide du copier-coller

L'utilisation de l'API DataTransfer avec des interactions de copier-coller est illustrée ci-dessous. Notez que l'objet DataTransfer est renvoyé par une propriété appelée clipboardData pour les événements du presse-papiers.

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

Formats de données personnalisés

Vous n'êtes pas limité aux types MIME primitifs, mais vous pouvez utiliser n'importe quelle clé pour identifier les données transférées. Cela peut être utile pour les interactions cross-browser au sein de votre application. Comme indiqué ci-dessous, vous pouvez transférer des données plus complexes à l'aide des fonctions JSON.stringify() et 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);
  }
});

Connecter le Web

Bien que les formats personnalisés soient idéaux pour la communication entre les applications que vous contrôlez, ils limitent également l'utilisateur lorsqu'il transfère des données vers des applications qui n'utilisent pas votre format. Si vous souhaitez vous connecter à des applications tierces sur le Web, vous avez besoin d'un format de données universel.

La norme JSON-LD (Linked Data) est un excellent candidat pour cela. Il est léger et facile à lire et à écrire en JavaScript. Schema.org contient de nombreux types prédéfinis qui peuvent être utilisés. Vous pouvez également définir des schémas personnalisés.

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

Lorsque vous utilisez les types Schema.org, vous pouvez commencer par le type générique Thing ou utiliser un type plus adapté à votre cas d'utilisation, comme Event, Person, MediaObject, Place ou même des types très spécifiques comme MedicalEntity si nécessaire. Lorsque vous utilisez TypeScript, vous pouvez utiliser les définitions d'interface des définitions de type schema-dts.

En transmettant et en recevant des données JSON-LD, vous contribuez à un Web plus connecté et ouvert. Avec des applications qui parlent le même langage, vous pouvez créer des intégrations profondes avec des applications externes. Vous n'avez pas besoin d'intégrations d'API complexes. Toutes les informations nécessaires sont incluses dans les données transférées.

Imaginez toutes les possibilités de transfert de données entre n'importe quelle application (Web) sans restriction : partage d'événements d'un agenda vers votre application de tâches préférée, ajout de fichiers virtuels à des e-mails, partage de contacts. Ce serait génial, n'est-ce pas ? Cela commence par vous ! 🙌

Problèmes

Bien que l'API DataTransfer soit disponible aujourd'hui, vous devez tenir compte de certains points avant de l'intégrer.

Compatibilité du navigateur

Les navigateurs pour ordinateur sont tous compatibles avec la technique décrite ci-dessus, contrairement aux appareils mobiles. Cette technique a été testée sur tous les principaux navigateurs (Chrome, Edge, Firefox, Safari) et systèmes d'exploitation (Android, ChromeOS, iOS, macOS, Ubuntu Linux et Windows), mais malheureusement, Android et iOS n'ont pas réussi le test. Bien que les navigateurs continuent d'évoluer, cette technique est pour l'instant limitée aux navigateurs pour ordinateur.

Visibilité

Le glisser-déposer et le copier-coller sont des interactions au niveau du système lorsque vous travaillez sur un ordinateur de bureau. Elles remontent aux premières interfaces utilisateur graphiques il y a plus de 40 ans. Réfléchissez au nombre de fois où vous avez utilisé ces interactions pour organiser des fichiers. Ce n'est pas encore très courant sur le Web.

Vous devrez informer les utilisateurs de cette nouvelle interaction et trouver des modèles UX pour la rendre reconnaissable, en particulier pour les personnes dont l'expérience avec les ordinateurs s'est jusqu'à présent limitée aux appareils mobiles.

Accessibilité

Le glisser-déposer n'est pas une interaction très accessible, mais l'API DataTransfer fonctionne également avec le copier-coller. Assurez-vous d'écouter les événements de copier-coller. Cela ne demande pas beaucoup de travail supplémentaire et vos utilisateurs vous en seront reconnaissants.

Sécurité et confidentialité

Vous devez tenir compte de certains aspects liés à la sécurité et à la confidentialité lorsque vous utilisez cette technique.

  • Les données du presse-papiers sont disponibles pour les autres applications sur l'appareil de l'utilisateur.
  • Les applications Web que vous faites glisser ont accès aux clés de type, mais pas aux données. Les données ne deviennent disponibles que lorsque vous les déposez ou les collez.
  • Les données reçues doivent être traitées comme n'importe quelle autre entrée utilisateur : nettoyez-les et validez-les avant de les utiliser.

Premiers pas avec la bibliothèque d'assistance Transmat

Êtes-vous impatient d'utiliser l'API DataTransfer dans votre application ? Consultez la bibliothèque Transmat sur GitHub. Cette bibliothèque Open Source harmonise les différences entre les navigateurs, fournit des utilitaires JSON-LD, contient un observateur pour répondre aux événements de transfert pour la mise en évidence des zones de dépôt et vous permet d'intégrer les opérations de transfert de données parmi les implémentations de glisser-déposer existantes.

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

Remerciements

Image principale de Luba Ertel sur Unsplash.