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

Limited availability
--------------------

This feature is not Baseline because it does not work in some of the most widely-used browsers.

* Learn more
* See full compatibility
* Report feedback
拡張機能でクリップボードを扱うのは、Web API の `document.execCommand` メソッド（非推奨）から `navigator.clipboard` メソッドに移行しています。

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

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

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

* テキストを扱う場合は `navigator.clipboard.readText()` と `navigator.clipboard.writeText()` が使えます。
* 画像、リッチテキスト、HTML、その他のリッチコンテンツを扱う場合は `navigator.clipboard.read()` と `navigator.clipboard.write()` が使えます。

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

* 画像を扱う場合は、クリップボードに画像を書き込むために `browser.clipboard.setImageData()` を使い、ウェブページに画像を貼り付けるために `document.execCommand("paste")` を使います。
* リッチコンテンツ（HTML、画像を含むリッチテキストなど）をクリップボードに書き込むには、`document.execCommand("copy")` か `document.execCommand("cut")` を使います。その後、`navigator.clipboard.read()` （推奨）または `document.execCommand("paste")` を使ってクリップボードからコンテンツを読み取ります。
クリップボードへの書き込み
-------------

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

### 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 の場合:

* `navigator.clipboard.write()` はサポートされていません。

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

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

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

### Clipboard API を使用する

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

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


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

### execCommand() を使用する

`document.execCommand("paste")` を使用するには、拡張機能には `"clipboardRead"` パーミッションが必要です。これは、`click` や `keypress` などのユーザーが生成したイベントハンドラーから `"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 with JavaScript enabled. Enable JavaScript to view data.

### webextensions.api.clipboard

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* Clipboard API
* Permissions API
* コンテンツを編集可能にする
* `contenteditable`