Surmonter les obstacles avec l'API DataTransfer

Permet à l'utilisateur de partager des données en dehors 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 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 glisser-déposer et de copier-coller sont souvent utilisées pour les interactions au sein d'une page afin de transférer du 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 glisser-déposer et de copier-coller intégrées au navigateur peuvent communiquer avec d'autres applications, Web ou autres, 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 vous explique tout ce que vous devez savoir.

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.

La réception du transfert de données fonctionne presque de la même manière que la fourniture. É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 vous la déposez dans la barre d'URL 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 des données en utilisant le 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 excellents 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 liées) est particulièrement adaptée à cet effet. Il est léger et facile à lire et à écrire en JavaScript. Schema.org contient de nombreux types prédéfinis que vous pouvez utiliser. 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 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. Avec des applications parlant 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.

Pensez à toutes les possibilités de transfert de données entre n'importe quelle application (Web) sans restriction: partager des événements d'un agenda avec votre application de tâches à faire préférée, joindre des fichiers virtuels à des e-mails, partager des contacts. C\'est bien cela ? Cela commence par vous ! 🙌

Problèmes

Bien que l'API DataTransfer soit disponible dès aujourd'hui, vous devez prendre en compte certains points avant de l'intégrer.

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. Ils remontent aux premières IUG il y a plus de 40 ans. Réfléchissez au nombre de fois où vous avez utilisé ces interactions pour organiser des fichiers. Cette pratique n'est pas encore très courante 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. Assurez-vous d'écouter les événements de copier-coller. Cela ne demande pas beaucoup d'efforts supplémentaires, et vos utilisateurs vous en seront reconnaissants.

Sécurité et confidentialité

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

  • Les données du presse-papiers sont disponibles pour les autres applications de 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 qu'en cas de glisser-déposer ou de collage.
  • Les données reçues doivent être traitées comme toute autre entrée utilisateur. Nettoyez-les et validez-les avant de les utiliser.

Premiers pas avec la bibliothèque d'assistance Transmat

Vous êtes impatient d'utiliser l'API DataTransfer dans votre application ? Consultez 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.