DataTransfer API を使用して障壁を取り払う

ブラウザ ウィンドウを越えてユーザーがデータを共有できるようにします。

HTML5 Drag and Drop APIクリップボード イベントの一部である DataTransfer API について聞いたことがある方もいらっしゃるでしょう。ソースと受信ターゲットの間でデータを転送するために使用できます。

対応ブラウザ

  • 3
  • 12
  • 3.5
  • 4

ソース

ドラッグ&ドロップとコピー&ペーストの操作は、単純なテキストを A から B に転送するためのページ内での操作によく使用されます。しかし、しばしば見落とされがちなのが、ブラウザ ウィンドウを超えて同じ操作を行える機能です。

ブラウザの組み込みのドラッグ&ドロップ操作とコピーと貼り付け操作はどちらも、他のアプリケーション(ウェブなど)と通信でき、どのオリジンにも関連付けられません。API は、データの転送先に応じて動作が異なる複数のデータエントリをサポートします。ウェブ アプリケーションは、受信イベントをリッスンする際に、転送されたデータを送受信できます。

この機能により、デスクトップのウェブ アプリケーションでの共有と相互運用性に対する考え方が変わります。アプリケーション間のデータ転送で、密結合な統合に依存する必要がなくなります。その代わりに、ユーザーが任意の場所にデータを転送するための完全な制御を提供できます。

DataTransfer API で可能なインタラクションの例。(動画に音声は含まれません)。

データの移行

まず、ドラッグ&ドロップまたはコピー&ペーストを実装する必要があります。以下の例はドラッグ&ドロップ操作を示していますが、コピー / 貼り付けのプロセスも同様です。Drag and Drop API になじみがない場合は、HTML5 のドラッグ&ドロップに関する記事で詳細が説明されていますのでご覧ください。

MIME タイプのキー付きデータを提供することで、外部アプリケーションと自由にやり取りできるようになります。ほとんどの WYSIWYG エディタ、テキスト エディタ、ブラウザは、以下の例で使用されている「プリミティブ」MIME タイプに応答します。

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

event.dataTransfer プロパティに注目してください。DataTransfer のインスタンスが返されます。後で説明するように、このオブジェクトは他の名前のプロパティによって返されることがあります。

データ転送の受信は、データ転送の送信とほぼ同じです。受信イベント(drop または paste)をリッスンし、キーを読み取ります。要素をドラッグすると、ブラウザはデータの type キーにのみアクセスできます。データ自体には、ドロップ後にのみアクセスできます。

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

アプリケーション全体で、次の 3 つの MIME タイプが幅広くサポートされています。

  • text/html: contentEditable 要素と、Google ドキュメントや Microsoft Word などのリッチテキスト(WYSIWYG)エディタで HTML ペイロードをレンダリングします。
  • text/plain: 入力要素の値、コードエディタのコンテンツ、text/html からのフォールバックを設定します。
  • text/uri-list: URL バーまたはブラウザページにドロップすると、URL に移動します。ディレクトリまたはデスクトップにドロップすると、URL ショートカットが作成されます。

WYSIWYG エディタで text/html が広く採用されているので、非常に便利です。HTML ドキュメントと同様に、データ URL または一般公開されている URL を使用してリソースを埋め込むことができます。これは、キャンバスなどから Google ドキュメントなどのエディタにビジュアルをエクスポートする場合に適しています。

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

コピーと貼り付けを使用して転送する

DataTransfer API でのコピーと貼り付けの操作を以下に示します。DataTransfer オブジェクトは、クリップボード イベントに対して clipboardData というプロパティによって返されます。

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

カスタムのデータ形式

プリミティブ MIME タイプに限定されませんが、任意のキーを使用して転送されたデータを識別できます。これは、アプリケーション内でブラウザをまたいだインタラクションに役立ちます。以下に示すように、JSON.stringify() 関数と 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);
  }
});

ウェブの接続

カスタム形式は、管理下にあるアプリケーション間の通信には適していますが、その形式を使用していないアプリケーションにデータを転送するときもユーザーが制限されます。ウェブ上でサードパーティ アプリケーションに接続する場合は、ユニバーサルなデータ形式が必要です。

これには、JSON-LD(Linked Data)標準が適しています。軽量で、JavaScript での読み取りと書き込みが簡単です。Schema.org には使用可能な多くの定義済みタイプが含まれており、カスタム スキーマ定義も使用できます。

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

Schema.org タイプを使用する場合は、汎用の Thing タイプから始めることも、必要に応じて EventPersonMediaObjectPlace などのユースケースに近いタイプを使用することも、MedicalEntity のような非常に具体的なタイプを使用することもできます。TypeScript を使用する場合は、schema-dts 型定義のインターフェース定義を使用できます。

JSON-LD データを送受信することで、より接続されたオープンなウェブをサポートできます。同じ言語を使用するアプリケーションを使用することで、外部アプリケーションとの緊密な統合を実現できます。複雑な API 統合は必要ありません。必要な情報はすべて、転送されるデータに含まれます。

カレンダーからお気に入りの ToDo アプリへのイベントの共有、メールへの仮想ファイルの添付、連絡先の共有など、任意の(ウェブ)アプリケーション間でデータを無制限に転送できるすべての可能性を考慮してください。そうだといいけど。まずはあなたから!🙌

懸念事項の件数

DataTransfer API は本日よりご利用いただけますが、統合する前に注意すべき点がいくつかあります。

ブラウザの互換性

上記の手法はパソコンのブラウザですべてサポートされていますが、モバイル デバイスではサポートされていません。この手法は、すべての主要なブラウザ(Chrome、Edge、Firefox、Safari)とオペレーティング システム(Android、ChromeOS、iOS、macOS、Ubuntu Linux、Windows)でテストされていますが、残念ながら Android と iOS ではテストに合格しませんでした。ブラウザの開発は続いていますが、現時点ではこの手法はパソコンのブラウザに限定されています。

見つけやすさ

ドラッグ&ドロップとコピー&ペーストは、デスクトップ パソコンで作業する際のシステムレベルの操作であり、40 年以上前に最初の GUI にまで遡ります。ファイル整理のために それらの操作が何回あるか考えてみてくださいウェブではあまり一般的ではありませんが、

この新しいインタラクションについてユーザーに説明し、特にこれまでパソコンの使用がモバイル デバイスに限定されていたユーザーにとっては、特に、このインタラクションを認識しやすい UX パターンを考案する必要があります。

ユーザー補助

ドラッグ&ドロップは簡単に操作できる操作ではありませんが、DataTransfer API はコピー&ペーストにも対応しています。コピー&ペーストのイベントをリッスンしてください。追加作業はそれほど必要ありません

セキュリティとプライバシー

この手法を使用する際には、セキュリティとプライバシーについて考慮すべき点がいくつかあります。

  • ユーザーのデバイス上の他のアプリでクリップボードのデータを利用できます。
  • ドラッグしようとしているウェブ アプリケーションは、データではなくタイプキーにアクセスできます。データはドロップまたは貼り付け時にのみ利用可能になります。
  • 受信したデータは、他のユーザー入力と同様に扱う必要があり、使用する前にサニタイズして検証する必要があります。

Transmat ヘルパー ライブラリのスタートガイド

アプリケーションで DataTransfer API を使用してみたいと思いませんか?GitHub の Transmat ライブラリを確認することを検討してください。このオープンソース ライブラリでは、ブラウザの違いを調整し、JSON-LD ユーティリティを提供し、ドロップ領域をハイライト表示する転送イベントに応答するオブザーバーが含まれています。また、既存のドラッグ&ドロップ実装間でデータ転送オペレーションを統合できます。

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

謝辞

ヒーロー画像(作成者: Luba ErtelUnsplash