クリップボードとのやりとり

拡張機能でクリップボードを扱うのは、Web API の document.execCommand メソッド(非推奨)から navigator.clipboard メソッドに移行しています。

メモ: navigator.clipboard API は最近追加された仕様であり、すべてのブラウザーで完全に実装されているとは限りません。この記事ではいくつかの制限事項を説明しますが、API があなたのニーズをサポートしていることを確認するために、使用する前に必ず各メソッドの互換性テーブルを確認するようにしてください。

2 つの API の違いは、document.execCommand がキーボードのコピー、カット、ペーストの操作に似ていて、ウェブページとクリップボード間でデータを交換するのに対し、navigator.clipboard はクリップボードとの間で任意のデータの書き込みと読み出しを行うことです。

navigator.clipboard は、読み書きのためのメソッドを個別に提供しています。

しかし、navigator.clipboard.readText()navigator.clipboard.writeText() はすべてのブラウザーで動作しますが、navigator.clipboard.read()navigator.clipboard.write() は動作するとは限りません。例えば、執筆時点の Firefox では、navigator.clipboard.read()navigator.clipboard.write() は完全に実装されていないため、次のことを留意する必要があります。

クリップボードへの書き込み

ここでは、クリップボードにデータを書き込むためのオプションについて説明します。

Clipboard API を使用する

Clipboard API は、拡張機能から任意のデータをクリップボードに書き込むものです。この API を使用するには、manifest.json ファイルに "clipboardRead" または "clipboardWrite" というパーミッションを設定する必要があります。この API は安全なコンテキストでのみ利用可能であるため、http: ページで動作するコンテンツスクリプトからは使用できず、https: ページでのみ使用できます。

ページスクリプトの場合、Web API の navigator.permissions を使用して "clipboard-write" パーミッションを要求する必要があります。そのパーミッションは、navigator.permissions.query() を使って確認することができます。

js
navigator.permissions.query({ name: "clipboard-write" }).then((result) => {
  if (result.state === "granted" || result.state === "prompt") {
    /* write to the clipboard now */
  }
});

メモ: clipboard-write のパーミッション名は Firefox ではサポートされておらず、Chromium ブラウザーでのみサポートされています。

この関数は、文字列を受け取り、それをクリップボードに書き込みます。

js
function updateClipboard(newClip) {
  navigator.clipboard.writeText(newClip).then(
    () => {
      /* clipboard successfully set */
    },
    () => {
      /* clipboard write failed */
    },
  );
}

execCommand() を使用する

document.execCommand() メソッドの "cut""copy" コマンドは、クリップボードの内容を選択した素材に置き換えるために使用されます。これらのコマンドは、ユーザーアクションに対する短時間のイベントハンドラー(例えば、クリックハンドラー)で特別な許可なしに使用することができます。

例えば、以下のような HTML を含むポップアップがあったとします。

html
<input id="input" type="text" /> <button id="copy">Copy</button>

"copy" ボタンで <input> 要素の内容をコピーさせるには、次のようなコードを使用します。

js
function copy() {
  let copyText = document.querySelector("#input");
  copyText.select();
  document.execCommand("copy");
}

document.querySelector("#copy").addEventListener("click", copy);

execCommand() の呼び出しはクリックイベントハンドラーの中にあるので、特別な権限は必要ありません。

しかし、その代わりに、アラームからコピーを起動させたとしましょう。

js
function copy() {
  let copyText = document.querySelector("#input");
  copyText.select();
  document.execCommand("copy");
}

browser.alarms.create({
  delayInMinutes: 0.1,
});

browser.alarms.onAlarm.addListener(copy);

ブラウザーによっては、うまく動作しないことがあります。Firefox では動作せず、コンソールに次のようなメッセージが表示されます。

document.execCommand('cut'/'copy') was denied because it was not called from inside a short running user-generated event handler.

このユースケースを有効にするには、"clipboardWrite" パーミッションを要求する必要があります。つまり "clipboardWrite" は、ユーザーアクションのための短時間のイベントハンドラーの外側でクリップボードに書き込むことを可能にします。

メモ: document.execCommand() は、type="hidden" の入力フィールド、HTML5 属性の "hidden"、または "display: none;" を使った CSS ルールにマッチするものでは機能しません。したがって、span, div, p タグに「クリップボードにコピー」ボタンを追加するには、入力の位置を絶対座標に設定し、ビューポートの外に移動させるなどの回避策をとる必要があります。

特定のブラウザーにおける留意事項

クリップボードなどの API は日進月歩で進化しているため、ブラウザーによって動作にばらつきがあります。

Chrome の場合:

  • ユーザーが作成したイベントハンドラーの外でクリップボードに書き込む場合でも、"clipboardWrite" は必要ありません。

Firefox の場合:

詳細はブラウザーの互換性を参照してください。

クリップボードからの読み込み

ここでは、クリップボードからデータを読み込んだり、貼り付けたりするためのオプションについて説明します。

Clipboard API を使用する

Clipboard API の navigator.clipboard.readText()navigator.clipboard.read() メソッドを使うと、安全なコンテキストでクリップボードから任意のテキストまたはバイナリーデータを読み取ることができます。これにより、編集可能な要素に貼り付けることなく、クリップボードのデータにアクセスすることができます。

一度 権限 API から "clipboard-read" パーミッションを取得すると、クリップボードから簡単に読み取ることができるようになります。例えば、このコードのスニペットはクリップボードからテキストを取得し、ID が "outbox" の要素の内容をそのテキストで置き換えます。

js
navigator.clipboard
  .readText()
  .then((clipText) => (document.getElementById("outbox").innerText = clipText));

execCommand() を使用する

document.execCommand("paste") を使用するには、拡張機能には "clipboardRead" パーミッションが必要です。これは、clickkeypress などのユーザーが生成したイベントハンドラーから "paste" コマンドを使用する場合でも同様です。

このような内容を含む HTML を考えてみましょう。

html
<textarea id="output"></textarea> <button id="paste">Paste</button>

ユーザーが "paste"<button> をクリックしたときに、クリップボードから ID が "output"<textarea> 要素の内容を設定するには、次のようなコードを使用します。

js
function paste() {
  let pasteText = document.querySelector("#output");
  pasteText.focus();
  document.execCommand("paste");
  console.log(pasteText.textContent);
}

document.querySelector("#paste").addEventListener("click", paste);

特定のブラウザーにおける留意事項

Firefox はバージョン 54 から "clipboardRead" パーミッションをサポートしていますが、コンテンツ編集可能モードの要素への貼り付けのみをサポートしており、コンテンツスクリプトの場合は <textarea> でのみ機能します。バックグラウンドスクリプトでは、どの要素もコンテンツ編集可能モードに設定できます。

ブラウザーの互換性

api.Clipboard

BCD tables only load in the browser

webextensions.api.clipboard

BCD tables only load in the browser

関連情報