Surmonter les obstacles avec l'API DataTransfer

Autorisez l'utilisateur à 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 glisser-déposer et des événements de presse-papiers. Il peut être utilisé pour transférer des données entre la source et les cibles réceptrices.

Navigateurs pris en charge

  • 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 au sein d'une page afin de transférer un texte simple de A à B. Mais ce qui est souvent négligé, c'est la possibilité d'utiliser ces mêmes interactions pour aller au-delà de la fenêtre du navigateur.

Les interactions de type glisser-déposer intégrées au navigateur et copier-coller peuvent communiquer avec d'autres applications, sur le Web ou ailleurs, et ne sont liées à aucune origine. L'API accepte plusieurs entrées de données avec des comportements différents en fonction de 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 le partage et l'interopérabilité dans les applications Web sur ordinateur. Le transfert de données entre les applications n'a plus besoin de s'appuyer sur des intégrations étroitement associées. Vous pouvez plutôt leur donner 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 glisser-déposer, mais le processus de copier-coller est similaire. Si vous ne connaissez pas bien l'API Drag and Drop, consultez l'article Explication du glisser-déposer HTML5, qui explique en détail le fonctionnement de cette API.

En fournissant des données chiffrées de 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.

Recevoir le transfert de données fonctionne presque de la même manière que le fournir. É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 un dépôt.

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 des éléments contentEditable et des éditeurs de texte enrichi (WYSIWYG) tels que Google Docs, Microsoft Word et d'autres.
  • text/plain: Définit la valeur des éléments d'entrée, le contenu des éditeurs de code et le remplacement à partir de text/html.
  • text/uri-list:permet d'accéder à l'URL lorsque l'utilisateur le place dans la barre d'adresse ou sur la page du navigateur. Un raccourci d'URL est créé lorsque vous déposez un fichier dans 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 avec l'exportation de 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 à l'aide d'un 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 de 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 inter-navigateurs dans 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 parfaits pour la communication entre les applications que vous contrôlez, ils limitent également l'utilisateur lors du transfert de 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 (données associées) 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, et les définitions de schéma personnalisées sont également disponibles.

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 proche de 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 plus ouvert. Lorsque vos applications parlent le même langage, vous pouvez créer des intégrations avancées avec des applications externes. Aucune intégration d'API complexe n'est nécessaire. Toutes les informations nécessaires sont incluses dans les données transférées.

Réfléchissez à 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 Liste de tâches préférée, ajout de fichiers virtuels à des e-mails, partage de contacts. C\'est bien cela ? C'est à vous de jouer ! 🙌

Problèmes

Bien que l'API DataTransfer soit disponible dès aujourd'hui, vous devez prendre connaissance de certains points avant de procéder à l'intégration.

Compatibilité du navigateur

Les navigateurs pour ordinateur sont tous très compatibles avec la technique décrite ci-dessus, contrairement aux appareils mobiles. La 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 Android et iOS n'ont malheureusement pas réussi le test. Les navigateurs continuent de se développer, mais pour le moment, cette technique est 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. Ces interactions remontent aux premières IUG il y a plus de 40 ans. Pensez 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 sensibiliser les utilisateurs à cette nouvelle interaction et élaborer des modèles d'expérience utilisateur pour les rendre reconnaissables, 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. Veillez à écouter les événements copier-coller. Cela ne demande pas beaucoup de travail supplémentaire, et vos utilisateurs vous remercieront de l'avoir ajouté.

Sécurité et confidentialité

Lorsque vous utilisez cette technique, vous devez tenir compte de certains aspects de sécurité et de confidentialité.

  • Les données du presse-papiers sont disponibles pour d'autres applications sur l'appareil de l'utilisateur.
  • Les applications Web que vous faites glisser ont accès aux touches de saisie, mais pas aux données. Les données ne sont disponibles que par glisser-déposer.
  • Les données reçues doivent être traitées comme toute autre entrée utilisateur. Elles doivent être nettoyées et validées avant d'être utilisées.

Premiers pas avec la bibliothèque d'assistance Transmat

Êtes-vous intéressé par l'utilisation de l'API DataTransfer dans votre application ? Vous pouvez consulter la bibliothèque Transmat sur GitHub. Cette bibliothèque Open Source aligne les différences entre les navigateurs, fournit des utilitaires JSON-LD, contient un observateur pour répondre aux événements de transfert afin de mettre en surbrillance les zones de dépôt et vous permet d'intégrer les opérations de transfert de données aux 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 par Luba Ertel sur Unsplash.