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

拡張機能でクリップボードを扱うのは、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

Report problems with this compatibility data on GitHub
desktopmobile
Chrome
Edge
Firefox
Opera
Safari
Chrome Android
Firefox for Android
Opera Android
Safari on iOS
Samsung Internet
WebView Android
WebView on iOS
Clipboard
read
formats.unsanitized parameter
Experimental
readText
Supports image/png MIME type
Supports text/html MIME type
Supports text/plain MIME type
write
writeText

Legend

Tip: you can click/tap on a cell for more information.

Full support
Full support
No support
No support
Experimental. Expect behavior to change in the future.
See implementation notes.

webextensions.api.clipboard

Report problems with this compatibility data on GitHub
desktopmobile
Chrome
Edge
Firefox
Opera
Safari
Firefox for Android
Safari on iOS
clipboard
setImageData

Legend

Tip: you can click/tap on a cell for more information.

Full support
Full support
No support
No support
See implementation notes.

関連情報