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

ユーザーがブラウザ ウィンドウの外部でデータを共有できるようにする。

DataTransfer API は、HTML5 Drag and Drop APIClipboard イベントの一部です。ソースと受信ターゲット間でデータを転送するために使用できます。

対応ブラウザ

  • Chrome: 3.
  • Edge: 12.
  • Firefox: 3.5。
  • Safari: 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 のインスタンスが返されます。ご覧のとおり、このオブジェクトは、他の名前のプロパティから返されることもあります。

データ転送の受信は、提供する場合とほぼ同じです。受信イベント(droppaste)をリッスンして、キーを読み取ります。要素の上にドラッグすると、ブラウザはデータの 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: HTML ペイロードを contentEditable 要素とリッチテキスト(WYSIWYG)エディタ(Google ドキュメント、Microsoft Word など)でレンダリングします。
  • 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(リンク データ)標準は、この目的に適しています。軽量で、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);

謝辞

UnsplashLuba Ertel によるヒーロー画像。