Async Clipboard API 向け SVG サポート

Async Clipboard API の Clipboard インターフェースは、システム クリップボードの内容に対する読み取り / 書き込みアクセスを提供します。これにより、ウェブ アプリケーションに切り取り、コピー、貼り付けの機能を実装できます。read() メソッドを呼び出してクリップボードのデータをアプリに貼り付け、write() メソッドを呼び出してデータをクリップボードにコピーできます。Async Clipboard API では、テキスト、Portable Network Graphics(PNG)形式の画像、サニタイズおよびサニタイズされていない HTMLウェブのカスタム形式に加え、SVG 画像のコピーと貼り付けもサポートされるようになりました。つまり、SVG 画像のコピーや貼り付けをSVG 画像としてコピーおよび貼り付けたりすることで、SVG 画像を扱うより自然に操作できるようになります。

SVG 機能検出のサポート

静的 ClipboardItem.supports() メソッドを呼び出して、必要な MIME タイプを渡すことで、SVG 画像(およびその他の MIME タイプ)のサポートを検出します。

const supportsSVG = () => {
  if (
    !('supports' in window.ClipboardItem) ||
    !window.ClipboardItem.supports('image/svg+xml')
  ) {
    return false;
  }
  return true;
};

SVG 画像をコピーする

ClipboardItem にオブジェクトを入力して、SVG 画像をコピーします。SVG 画像データを含む blob は値とその blob の型(この場合は 'image/svg+xml')です。

copyButton.addEventListener('click', async () => {
  if (!supportsSVG()) {
    return;
  }
  try {
    const blob = await fetch(img.src).then((response) => response.blob());
    await navigator.clipboard.write([
      new window.ClipboardItem({
        [blob.type]: blob,
      }),
    ]);
  } catch (err) {
    console.error(err.name, err.message);
    alert(err.message);
  }
});

SVG 画像を貼り付ける

SVG 画像を貼り付けるには、クリップボードから ClipboardItem を読み込み、getType() メソッドで目的のタイプ(この場合は 'image/svg+xml')を取得します。これは blob を返します。blob URL に変換されると、<img>src 属性に割り当てることができます。

pasteButton.addEventListener('click', async () => {
  if (!supportsSVG()) {
    return;
  }
  const [clipboardItem] = await navigator.clipboard.read();
  const svgBlob = await clipboardItem.getType('image/svg+xml');
  if (!svgBlob) {
    alert('No SVG in the clipboard.');
    return;
  }
  const image = document.createElement('img');
  const blobURL = URL.createObjectURL(svgBlob);
  image.addEventListener('load', () => {
    URL.revokeObjectURL(blobURL);
  });
  image.src = blobURL;
});

サニタイズ

SVG は強力な形式であり、たとえば埋め込みスクリプトが可能です。これは、ユーザーが提供元不明のコンテンツを貼り付けた場合に危険であり、ブラウザがサニタイズのステップを実行する可能性があります。データがコピーされると、Async Clipboard API により整形式の SVG ドキュメントが生成され、クリップボードに書き込まれます。データが貼り付けられると、厳密に処理された SVG フラグメントがフラグメント パーサーによって生成されます。そのため、貼り付け操作の前に onclick イベント ハンドラ属性はそのまま残りますが、貼り付け時に削除されます。

クリップボードの内容を検査している、macOS のクリップボード ビューア アプリ。SVG の click イベント リスナー属性がまだ残っていることを示しています。
クリップボードの内容を検査する macOS のクリップボード ビューア アプリ。SVG の click イベント リスナー属性がまだ残っていることを示しています。

デモ

Glitch のデモで SVG をコピーして貼り付ける方法を確認する。その仕組みについては、ソースコードをご覧ください。コピーして貼り付けの前と後に、いずれかの円をクリックしてみてください。貼り付けると、危険性のある onclick イベント ハンドラ属性が削除されます。

謝辞

Chromium での Async Clipboard API の SVG サポートは、Microsoft Edge チームによって実装されました。この投稿は Rachel Andrew と Anupam Snigdha によってレビューされました。