JavaScriptからクリップボードを操作するClipboard API ドラフト和訳

以下は[Clipboard API and events](https://www.w3.org/TR/clipboard-apis/)の2018/08/27時点での最新版、`2017/09/29 Working Draft`の日本語訳です。
これは、これまで共通化されていなかったクリップボードへの読み書きを一貫するのが目的のAPIです。

現在このAPIのステータスは[作業草案](https://ja.wikipedia.org/wiki/W3C%E5%8B%A7%E5%91%8A)という初期段階ですが、既に多くのブラウザで[一部実装](https://caniuse.com/#search=clipboard%20API)されています。
最新の編集者草案は[こちら](https://w3c.github.io/clipboard-apis/)にあります。


# 1 Introduction

このセクションは規定ではなく参考情報です。

この仕様は、カット、コピー、ペーストといったクリップボード操作を定義し、それらをWebアプリケーションから操作する高度な機能を提供します。
このドキュメントの目的は、既存の実装となるべく互換を持たせることです。

# 2 Use Cases

このセクションは規定ではなく参考情報です。

デフォルトのクリップボード操作(カット/コピー/ペースト)を変更したい多くのユースケースがあります。
どのような操作ができるかの事例を幾つか用意しましたが、全てがこの仕様書でサポートされているとは限りません。

## 2.1 Rich content editing

ハイパーリンクやその他のドキュメント構造を含むテキストをコピーする際、重要な情報を保持するためにコピー内容を再フォーマットできると役に立つでしょう。

## 2.2 Graphics with built-in semantics

リッチテキストや[SVG11](https://www.w3.org/TR/SVG11/)のようなグラフィックコンテンツを操作するWebアプリケーションは、レンダリングされたコンテンツだけではなく、それ以上の構造をコピーを可能にする機能があると便利になることでしょう。

## 2.3 Mathematical information

数式などのコンテンツは、テキストをコピーして別のアプリケーションに貼り付けるだけで、式のほとんどが失われてしまいます。
MathMLをコピーする際に、プレーンテキストとして意味が通るようにコピーされるように変換する需要があるでしょう。
例えば、累乗をプレーンテキストに渡したら`^`に変換してほしいです。
XMLはクリップボードにコピーしたあと、ペースト時に適切な形式に変換できるようすることもできます。

# 3 Terminology

`編集可能なテキスト(editable context)`とは、[ContentEditable](http://w3c.github.io/editing/contentEditable.html#dfn-editing-host)、textarea、input要素のうち"type"に"text"、"search"、"tel"、"url"、"email"、"password"、"number"のいずれかが指定されているものを示します。

# 4 Model

プラットフォームは`システムクリップボード(system clipboard)`を提供します。
[システムクリップボード](https://www.w3.org/TR/clipboard-apis/#system-clipboard)は`システムクリップボードデータ(system clipboard data)`と呼ばれる要素を置いておけるListです。
[システムクリップボードデータ](https://www.w3.org/TR/clipboard-apis/#system-clipboard-data)は、クリップボードの内容を保持している[DataTransfer](https://html.spec.whatwg.org/multipage/dnd.html#datatransfer)オブジェクトです。

# 5 Clipboard Events

## 5.1 Clipboard event interfaces

`ClipboardEvent`インターフェイスは[Event](https://dom.spec.whatwg.org/#event)インターフェイスを継承します。

```idl
  dictionary ClipboardEventInit : EventInit {
    DataTransfer? clipboardData = null;
  };
```

[DataTransfer](https://html.spec.whatwg.org/multipage/dnd.html#datatransfer)はイベントのデータとメタデータを保持するオブジェクトです。

```idl
  [Constructor(DOMString type, optional ClipboardEventInit eventInitDict), Exposed=Window]
  interface ClipboardEvent : Event {
    readonly attribute DataTransfer? clipboardData;
  };
```

clipboardData属性は[DataTransfer](https://html.spec.whatwg.org/multipage/dnd.html#datatransfer)インターフェイスのインスタンスで、ユーザが行ったカット、コピー、ペーストの操作時にスクリプトがシステムクリップボードデータを操作することを可能にします。
"drag data store"は、システムクリップボードのフィルタリングされたビューで、スクリプトが安全にアクセスできる[mandatory data types](https://www.w3.org/TR/clipboard-apis/#mandatory-data-types)データ型のみが格納されます。
[合成イベント](https://developer.mozilla.org/ja/docs/Web/Guide/Events/Creating_and_triggering_events)の場合、"drag data store"にはそのイベントによって作られたデータが含まれています。

`clipboardData`オブジェクトは[items](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-items-2)と[files](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-files-2)プロパティを持ち、マルチパートデータやテキスト以外の形式のデータをクリップボードで操作することができます。

このインターフェイスを使って[イベントを発火](https://dom.spec.whatwg.org/#constructing-events)できます。
以下に例を示します。

```js:EXAMPLE1
var pasteEvent = new ClipboardEvent('paste');
pasteEvent.clipboardData.items.add('My string', 'text/plain');
document.dispatchEvent(pasteEvent);
```

注意：合成イベントは実際にクリップボードを変更することはありません。
つまり、上のスクリプトでは貼り付けイベントは発生しますが、データがドキュメントに貼り付けられることはありません。

## 5.2 Clipboard events

### 5.2.1 The clipboardchange event

clipboardchangeイベントは、システムクリップボードの内容が変化するたびに発生します。
全てを網羅してはいませんが、以下のような原因で発火します。
・ユーザがカットやコピー操作を行った
・スクリプトでAsynchronous Clipboard APIを使ってクリップボードに書き込んだ
・ブラウザ外でクリップボードの変更があった

ブラウザ外のでクリップボードの変更が行われた場合、clipboardchangeイベントはブラウザがアクティブに戻ったときに発生しなければなりません(MUST)。

合成イベントおよびコピーイベントはシステムクリップボードの内容を変更しないため、clipboardchangeイベントは発生しません。

### 5.2.2 The copy event

ユーザがコピー操作を行うと、ブラウザでは`copy`というイベントが発生します。
イベントをキャンセルしないかぎり、現在選択中のデータがクリップボードにコピーされます。
現在選択している範囲には何の影響もありません。

コピーイベントはバブリング、キャンセルが可能です。

このイベントの動作の詳細については、`8.1 The copy action`を参照してください。

合成コピーイベントを手動で作成して発火することはできますが、システムクリップボードに影響を与えることはできません。

### 5.2.3 The cut event

ユーザがカット操作を行うと、ブラウザでは`cut`というイベントが発生します。

編集可能なコンテキストを選択している場合、イベントをキャンセルしないかぎり、現在選択中のデータがクリップボードにコピーされます。
選択範囲のドキュメントは削除されます。
cutイベントは、選択したデータが削除される前に発生します。
イベントの完了時に選択範囲が削除されます。

編集不可能なコンテキストを選択している場合、clipboardDataは空のリストになります。
この場合でもイベント自体は発生することに注意してください。

カットイベントはバブリング、キャンセル可能です。

このイベントの動作の詳細については、`8.2 The cut action`を参照してください。

合成カットイベントを手動で作成して発火することはできますが、ドキュメントおよびシステムクリップボードに影響を与えることはできません。

### 5.2.4 The paste event

ユーザがペースト操作を行うと、ブラウザでは`paste`というイベントが発生します。
pasteイベントは、クリップボードのデータがドキュメントに挿入される前に発生します。

カーソルが編集可能なコンテキスト上にある場合、コンテキストがサポートしている中で最も適切なフォーマットでクリップボードデータを挿入します。
編集不可能なコンテキスト上にある場合、挿入はされませんが、ペーストイベント自体は発生します。

ペーストイベントはバブリング、キャンセル可能です。

このイベントの動作の詳細については、`8.3 The paste action`を参照してください。

合成ペーストイベントを手動で作成して発火することはできますが、ドキュメントに影響を与えることはできません。

## 5.3 Integration with other scripts and events

### 5.3.1 Event handlers that are allowed to modify the clipboard

イベントハンドラは、次の何れかに該当する場合、クリップボードにデータを書き込むことができます。

・ユーザ自身の操作によってイベントが発動している。メニューのコピー項目、Ctrl+Cのショートカットキーなど。
・スクリプトが、[ポップアップ](https://www.w3.org/TR/html5/browsers.html#allowed-to-show-a-popup)表示可能なスレッドから呼び出されている。

実装は、イベントの発動元がユーザの意思による操作であると確信できる場合、クリップボードの中身を変更することが許されます。
実装はまた、特定のサイトおよびアプリケーションに対して、イベントの発動元にかかわらずクリップボードの中身を変更する許可を与えることができます。

合成カット、コピーイベントはシステムクリップボードデータを変更してはいけません(MUST NOT)。

### 5.3.2 Event handlers that are allowed to read from clipboard

イベントハンドラは、次の何れかに該当する場合、クリップボードからデータを読み込むことができます。

・ユーザ自身の操作によってイベントが発動している。メニューの貼り付け項目、Ctrl+Vのショートカットキーなど。
・スクリプトが、クリップボードの中身を読み取る権限を与えたサイト上で実行されている。
・アプリケーションが、クリップボードの中身を読み取る権限を与えたアプリ内で実行されている。

合成ペーストイベントはシステムクリップボードデータにアクセスしてはいけません(MUST NOT)。

### 5.3.3 Integration with rich text editing APIs

実装が`document.execCommand()`コマンドなどのscripting APIを呼び出すことでカット・コピー・ペーストに対応した場合、コマンドが呼び出された際に対応したクリップボードイベントを発火しなければなりません(MUST)。

scripting APIからのコマンド呼び出しを対応する方法は以下のとおりです。

・対応するアクションを同期実行する。
・APIの返り値をコマンドの返り値とする。

注意：scripting APIから呼び出されたカット・コピーイベントは、ユーザが許可を与えたイベントから発火した、もしくは実装が許可を与えている場合にのみ、クリップボードを変更することができます。
ペーストイベントは、許可が与えられている場合にのみクリップボードにアクセスできます。
クリップボードに読み取り/書き込み許可を与える方法の実装については、この仕様の範囲外です。

### 5.3.4 Interaction with other events

キーボード入力によってクリップボード操作が行われた場合、実装は該当するクリップボードイベントを発生させる必要があります(MUST)。
イベントは非同期ですが、対応するキーのkeyupイベントより先に発生させなければなりません(MUST)。

カット・コピー操作は既存のtextInput・input・change・validation events・DOMCharacterDataModified・DOMNodeRemoved・DOMNodeInsertedといった多くの入力イベントに関連付いている場合があります。
それらのイベントは、カット・コピーのクリップボードイベントが終わるまでキューで待機します。

実装は、textInput・input・change・validation eventsなど他の入力関連イベントを発生させてはいけません(MUST NOT)。

### 5.3.5 Event listeners that modify selection or focus

イベントリスナーが選択範囲もしくは[フォーカス可能領域](https://html.spec.whatwg.org/multipage/interaction.html#focusable-area)を変更した場合、クリップボードアクションは変更された選択範囲を保たなければなりません(MUST)。

# 6 Synchronous Clipboard API

同期クリップボードAPIを使用すると、デフォルトのカット、コピー、ペーストの動作をオーバーライドすることができます。

クリップボードへのアクセスは標準の[DataTransfer](https://html.spec.whatwg.org/multipage/dnd.html#datatransfer).itemsを使用し、ClipboardEvent.clipboardData属性を変更します。
結果として、同期クリップボードAPIはClipboardEventハンドラから見えるコンテキストのみアクセスできます。

注意：ClipboardEventハンドラの外にあるデータにアクセスしたい場合は、§7 Asynchronous Clipboard APIを参照してください。

## 6.1 Overriding the copy event

デフォルトのコピーイベントをオーバーライドする場合、copyイベントハンドラを追加し、デフォルト動作を防ぐために[preventDefault()](https://dom.spec.whatwg.org/#dom-event-preventdefault)をコールする必要があります。

システムクリップボードをclipboardData内のデータで更新するには、イベントのキャンセルが必要です。
ClipboardEventがキャンセルされない場合、かわりに現在選択中のデータがコピーされます。

```js:EXAMPLE2
// コピーイベントの上書き
document.addEventListener('copy', function(e) {
  // e.clipboardDataは最初は空だが、コピーしたい任意のデータをセットすることができる
  e.clipboardData.setData('text/plain', 'Hello, world!');
  e.clipboardData.setData('text/html', '<b>Hello, world!</b>');

  // 入れないと現在選択中のテキストで上書きされる
  e.preventDefault();
});
```

## 6.2 Overriding the cut event

デフォルトのカットイベントをオーバーライドする場合、cutイベントハンドラを追加し、デフォルト動作を防ぐために[preventDefault()](https://dom.spec.whatwg.org/#dom-event-preventdefault)をコールする必要があります。

システムクリップボードをclipboardData内のデータで更新するには、イベントのキャンセルが必要です。
ClipboardEventがキャンセルされない場合、かわりに現在選択中のデータがコピーされます。

カットイベントをキャンセルすると、ドキュメントは更新されなくなります。
つまり現在選択中のテキストは削除されません。
必要であれば、現在選択されているテキストを削除するためにドキュメントを手動で更新する必要があります。

```js:EXAMPLE3
// カットイベントの上書き
document.addEventListener('cut', function(e) {
  // e.clipboardDataは最初は空だが、コピーしたいデータをセットすることができる
  e.clipboardData.setData('text/plain', 'Hello, world!');
  e.clipboardData.setData('text/html', '<b>Hello, world!</b>');
  
  // 現在選択中のドキュメントを手動で削除
  deleteCurrentDocumentSelection();
  
  // 入れないと現在選択中のテキストが上書きされる
  e.preventDefault();
});
```

## 6.3 Overriding the paste event

デフォルトのペーストイベントをオーバーライドする場合、pasteイベントハンドラを追加し、デフォルト動作を防ぐために[preventDefault()](https://dom.spec.whatwg.org/#dom-event-preventdefault)をコールする必要があります。

ドキュメントをシステムクリップボードのデータで上書きしないためには、イベントのキャンセルが必要です。

ペーストイベントをキャンセルすると、ドキュメントは何も更新されません。
必要であれば、ドキュメントを更新するために手動でデータを貼り付ける必要があります。

ペーストイベントの間、[drag data store mode](https://html.spec.whatwg.org/multipage/interaction.html#drag-data-store-mode)フラグは[Read Only](https://html.spec.whatwg.org/multipage/interaction.html#concept-dnd-ro)にされているため、[setData()](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-setdata-2)を呼んでもクリップボードのデータを更新することはできません。

```js:EXAMPLE4
// ペーストイベントの上書き
document.addEventListener('paste', function(e) {
  // e.clipboardDataには貼り付けようとしているデータが入ってくる
  if (e.clipboardData.types.indexOf('text/html') > -1) {
    var oldData = e.clipboardData.getData('text/html');
    var newData = '<b>Ha Ha!</b> ' + oldData;

    // デフォルト動作のかわりに手動でデータを貼り付ける
    pasteClipboardData(newData);

    // デフォルト動作を停止
    e.preventDefault();
  }
```

# 7 Asynchronous Clipboard API

## 7.1 Navigator Interface

```idl
partial interface Navigator {
  [SecureContext, SameObject] readonly attribute Clipboard clipboard;
};
```

### 7.1.1 clipboard

clipboard属性は、[Navigator](https://html.spec.whatwg.org/multipage/system-state.html#navigator).Clipboardオブジェクトを返す必要があります(MUST)。

## 7.2 Clipboard Interface

```idl
[SecureContext, Exposed=Window] interface Clipboard : EventTarget {
  Promise<DataTransfer> read();
  Promise<DOMString> readText();
  Promise<void> write(DataTransfer data);
  Promise<void> writeText(DOMString data);
};
```

### 7.2.1 read()

read()メソッドは、以下を実装する必要があります(MUST)。

1 新しく[Promise](http://tc39.github.io/ecma262/#sec-promise-objects)`p`を生成する。
2 readパーミッションを確認し、falseであればpをrejectする。
3 以下を[並列実行](https://html.spec.whatwg.org/multipage/infrastructure.html#in-parallel)する。
3.1 システムクリップボードのデータをdataにコピーする。
3.2 pをresolveする。
4.pをreturnする。

```js:EXAMPLE5
navigator.clipboard.read().then(function(data) {
  for (var i = 0; i < data.items.length; i++) {
    if (data.items[i].type == "text/plain") {
      console.log("Your string: ", data.items[i].getAs("text/plain"));
    } else {
      console.error("No text/plain data on clipboard.");
    }
  }
});
```

### 7.2.2 readText()

readText()メソッドは、以下を実装する必要があります(MUST)。

1 新しく[Promise](http://tc39.github.io/ecma262/#sec-promise-objects)`p`を生成する。
2 readパーミッションを確認し、falseであればpをrejectする。
3 以下を[並列実行](https://html.spec.whatwg.org/multipage/infrastructure.html#in-parallel)する。
3.1 システムクリップボードのデータをdataにコピーする。
3.2 textDataを空にする。
3.3 data.[items](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-items-2)が"text/plain"のtextItemを含んでいる場合
3.3.1 該当のtextItemをtextDataにコピーする。
3.4 pをresolveする。
4 pをreturnする。

```js:EXAMPLE6
navigator.clipboard.read().then(function(data) {
  console.log("Your string: ", data);
});

```

### 7.2.3 write(data)

write(data)メソッドは、以下を実装する必要があります(MUST)。

1 新しく[Promise](http://tc39.github.io/ecma262/#sec-promise-objects)`p`を生成する。
2 writeパーミッションを確認し、falseであればpをrejectする。
3 以下を[並列実行](https://html.spec.whatwg.org/multipage/infrastructure.html#in-parallel)する。
3.1 cleanItemListを空の[DataTransferItemList](https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist)にする。
3.2 全てのdata.[items](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-items-2)について以下を実行する。
3.2.1 itemをサニタイズしてcleanItemにコピーする。
3.2.2 コピーできなければpをrejectする。
3.2.3 cleanItemをcleanItemListに追加する。
3.3 cleanItemListをシステムクリップボードの[items](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-items-2)と入れ替える。
3.4 pをresolveする。
4 pをreturnする。

```js:EXAMPLE7
var data = new DataTransfer();
data.items.add("text/plain", "Howdy, partner!");
navigator.clipboard.write(data).then(function() {
  console.log("Copied to clipboard successfully!");
}, function() {
  console.error("Unable to write to clipboard. :-(");
});
```

### 7.2.4 writeText(data)

writeText(data)メソッドは、以下を実装する必要があります(MUST)。

1 新しく[Promise](http://tc39.github.io/ecma262/#sec-promise-objects)`p`を生成する。
2 writeパーミッションを確認し、falseであればpをrejectする。
3 以下を[並列実行](https://html.spec.whatwg.org/multipage/infrastructure.html#in-parallel)する。
3.1 newItemListを空の[DataTransferItemList](https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist)にする。
3.2 新たな[DataTransferItem](https://html.spec.whatwg.org/multipage/dnd.html#datatransferitem)オブジェクトnewItemを作成し、[drag data item kind](https://html.spec.whatwg.org/multipage/interaction.html#drag-data-item-kind)をstringに、[drag data item type string]を"text/plain"にする。
3.3 newItem.dataにdataをセットする。
3.4 newItemをnewItemListに追加する。
3.5 newItemListをシステムクリップボードの[items](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-items-2)と入れ替える。
3.6 pをresolveする。
4 pをreturnする

・
・[DataTransferItem](https://html.spec.whatwg.org/multipage/dnd.html#datatransferitem)を取り出しnewItemに入れ、テキストの形式を"text/plain"にする。
・newItemをnewItemListに追加する。
・[システムクリップボード](https://www.w3.org/TR/clipboard-apis/#system-clipboard-data)の[データ](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-items-2)をnewItemListに入れ替える


```js:EXAMPLE8
navigator.clipboard.writeText("Howdy, partner!").then(function() {
  console.log("Copied to clipboard successfully!");
}, function() {
  console.error("Unable to write to clipboard. :-(");
});
```

# 8 Clipboard Actions

このセクションでは、クリップボードアクションおよびイベントディスパッチの処理モデルを定義します。

各クリップボードアクションは`script-triggered`と`script-may-access-clipboard`のふたつのフラグを所有します。

script-triggeredフラグは、`document.execCommand()`のようにアクションがスクリプトから実行された場合に設定されます。
クリップボードとやりとりするAPIは、今後実装されるものも含め、必要に応じてscript-triggeredフラグを設定しなければなりません(MUST)。

script-may-access-clipboardフラグは以下の場合に設定されます。
・アクションがcopyもしくはcutであり、[クリップボードの変更が許可されている](https://www.w3.org/TR/clipboard-apis/#allowed-to-modify-the-clipboard)場合に設定される。
・アクションがpasteであり、[クリップボードからの読み取りが許可されている](https://www.w3.org/TR/clipboard-apis/#allowed-to-read-from-clipboard)場合に設定される。

## 8.1 The copy action

copyアクションは以下のステップで実行されます。

1 `script-triggered`が設定されているならば、
1.1 `script-may-access-clipboard`が設定されていないならば、
1.1.1 falseを返して処理を終了する。
2 [copy](https://www.w3.org/TR/clipboard-apis/#copy)の[クリップボードイベント](https://www.w3.org/TR/clipboard-apis/#fire-a-clipboard-event)を発火する。
3 イベントがキャンセルされなかったならば、
3.1 選択している内容があるならばクリップボードにコピーする。Webページが選択されている場合は`text/html`と`text/plain`の両形式を作成する必要がある。
3.2 [clipboardchange](https://www.w3.org/TR/clipboard-apis/#clipboardchange)の[クリップボードイベント](https://www.w3.org/TR/clipboard-apis/#fire-a-clipboard-event)を発火する。
4 イベントがキャンセルされたのであれば、
4.1 [クリップボードへの書き込み](https://www.w3.org/TR/clipboard-apis/#write-content-to-the-clipboard)アルゴリズムを呼び出し、[DataTransferItemList](https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist)、`clear-was-called`フラグ、`types-to-clear`リストを渡す。
5 trueを返す。

## 8.2 The cut action

cutアクションは以下のステップで実行されます。

1 `script-triggered`が設定されているならば、
1.1 `script-may-access-clipboard`が設定されていないならば、
1.1.1 falseを返して処理を終了する。
2 [copy](https://www.w3.org/TR/clipboard-apis/#cut)の[クリップボードイベント](https://www.w3.org/TR/clipboard-apis/#fire-a-clipboard-event)を発火する。
3 イベントがキャンセルされなかったならば、
3.1 選択している範囲が[編集可能なコンテキスト](https://www.w3.org/TR/clipboard-apis/#editable-context)であるならば、
3.1.1 選択している内容があるならばクリップボードにコピーする。Webページが選択されている場合は`text/html`と`text/plain`の両形式を作成する必要がある。
3.1.2 選択範囲のコンテンツを削除する。
3.1.3 [clipboardchange](https://www.w3.org/TR/clipboard-apis/#clipboardchange)の[クリップボードイベント](https://www.w3.org/TR/clipboard-apis/#fire-a-clipboard-event)を発火する。
3.1.4 ドキュメントの変更によって発生するイベントを実行させるため、タスクをキューに入れる。詳細は[5.3](https://www.w3.org/TR/clipboard-apis/#integration-with-other-scripts-and-events)を参照。
3.2 選択している範囲が編集可能でなければ、
3.2.1 falseを返す。
4 イベントがキャンセルされたのであれば、
4.1 [クリップボードへの書き込み](https://www.w3.org/TR/clipboard-apis/#write-content-to-the-clipboard)アルゴリズムを呼び出し、[DataTransferItemList](https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist)、`clear-was-called`フラグ、`types-to-clear`リストを渡す。
4.2 [clipboardchange](https://www.w3.org/TR/clipboard-apis/#clipboardchange)の[クリップボードイベント](https://www.w3.org/TR/clipboard-apis/#fire-a-clipboard-event)を発火する。
5 trueを返す。

## 8.3 The paste action

サイトおよびアプリがクリップボードからデータを読み取ることができる`script-may-access-clipboard`フラグは、その許可メカニズムの実装に依存します。
pasteアクションがスクリプトから呼び出された場合、実装はユーザの許可なしにクリップボードを読み込み可能にしてはいけません(MUST NOT)。
アクセスがまだ許可されていない場合、許可を求めるプロンプトには、スクリプトの対象となるホスト名が含まれていなければなりません(MUST)。

pasteアクションは以下のステップで実行されます。

1 `script-triggered`が設定されているならば、
1.1 `script-may-access-clipboard`が設定されていないならば、
1.1.1 falseを返して処理を終了する。
2 [paste](https://www.w3.org/TR/clipboard-apis/#paste)の[クリップボードイベント](https://www.w3.org/TR/clipboard-apis/#fire-a-clipboard-event)を発火する。
3 イベントがキャンセルされなかったならば、
3.1 選択している範囲がペースト可能な[編集可能なコンテキスト](https://www.w3.org/TR/clipboard-apis/#editable-context)であるならば、
3.1.1 クリップボードに存在するデータから最も適切な形式のコンテンツをペーストする。
3.1.2 ドキュメントの変更によって発生するイベントを実行させるため、タスクをキューに入れる。詳細は[5.3](https://www.w3.org/TR/clipboard-apis/#integration-with-other-scripts-and-events)を参照。
3.2 選択している範囲が編集可能でなければ、
3.2.1 falseを返す。
4 イベントがキャンセルされたのであれば、
4.1 falseを返す。
5 trueを返す。


# 9 Clipboard Permissions

このセクションは、クリップボードAPIへのアクセスをコントロールするclipboard permissionsについて定義します。

注意：現在、clipboard permissionsはAsync Clipboard APIにのみ適用されます。
今後この仕様は更新され、クリップボードにアクセスする全てのアクションに適用される予定です。

## 9.1 Clipboard read permission

クリップボードの読み取りパーミッションを確認する手順。

1 フルアクセス権限`{ name: "clipboard", access: "full" }`をチェックする。
2 値が"denied"であればfalseを返す。
3 値が"granted"であればtrueを返す。
4 値が"prompt"であれば、
4.1 現在のスクリプトが、ユーザ操作もしくはOSによる貼り付け操作であれば、systemPasteをtrueにする。
4.2 systemPasteがtrueであればtrueを返す。
4.3 フルアクセス権限の許可をユーザに問い合わせる。
4.4 問い合わせの結果をフルアクセス権限`{ name: "clipboard", access: "full" }`に書き込む。
5 フルアクセス権限の値が"granted"であればtrueを返す。
6 falseを返す。

## 9.2 Clipboard write permission

クリップボードの書き込みパーミッションを確認する手順。

1 フルアクセス権限`{ name: "clipboard", access: "full" }`をチェックする。
2 書き込み権限`{ name: "clipboard", access: "write" }`をチェックする。
3 フルアクセス権限の値が"granted"であればtrueを返す。
4 書き込み権限の値が"denied"であればfalseを返す。
5 現在のスクリプトが、ユーザ操作によって起動したものでなければfalseを返す。
6 値が"prompt"であれば、
6.1 書き込み権限の許可をユーザに問い合わせる。
6.2 問い合わせの結果を書き込み権限`{ name: "clipboard", access: "write" }`に書き込む。
7 書き込み権限の値が"granted"であればtrueを返す。
8 falseを返す。


# 10 Mandatory data types

実装は、OSクリップボードで使用される以下のデータ型を認識し、pasteイベントにおいて[DataTransferItemList](https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist)を正しく読み込むことができなければなりません(MUST)。
またcopyおよびcutイベントにおいて、正しく書き込むことができなければなりません(MUST)。

## 10.1 Reading from the clipboard

クリップボードに以下のネイティブ型が存在した場合、pasteイベントは対応するデータ型で対象を読み込む必要があります。

・text/plain
・text/uri-list
・text/csv
・text/css
・text/html
・application/xhtml+xml
・image/png
・image/jpg, image/jpeg
・image/gif
・image/svg+xml
・application/xml, text/xml
・application/javascript
・application/json
・application/octet-stream

## 10.2 Writing to the clipboard

copyおよびcutイベント中に以下のデータ型が[DataTransfer](https://html.spec.whatwg.org/multipage/dnd.html#datatransfer)に追加された場合、対応するネイティブ型としてクリップボードに書き込む必要があります。

・text/plain
・text/uri-list
・text/csv
・text/html
・image/svg+xml
・application/xml, text/xml
・application/json

注意：信頼できないスクリプトがクリップボードに書き込むことのできるデータ型は、セキュリティ上の理由から制限されています。
信頼できないスクリプトはローカルアプリの脆弱性を悪用しようとする可能性があります。

# 11 Security Considerations

Web制作者がユーザのコピーした内容を改変したり、選択していないものをクリップボードに入れたり、ペーストを無制限に許可したりすると、セキュリティとプライバシーに関する様々な懸念が生じます。
例として、ユーザがURLを選択してコピーしようとすると、コピーしようとした内容とは別のURLがクリップボードにコピーされたりといったことが起こります。
予期せぬ結果を与えるだけではなく、フィッシングに使われたりと、様々な問題が発生するでしょう。

## 11.1 Pasting HTML and multi-part data

このセクションは規定ではなく参考情報です。

リッチテキストやマルチパートデータをペーストすることには多くのセキュリティリスクが存在します。
・ユーザに気付かれないよう、`<input type="hidden">`のような隠された領域に機密情報をペーストされる可能性があります。
・ユーザは、悪質なJavaScriptを信頼できるページにペーストすることがあります。
・実装が、ユーザが公開するつもりのないローカルファイルへのアクセス許可を与える場合があります。

どのアクセスポリシーを適用するかについては、以下のような要点を考える必要があります。

・ペーストされるデータの起源
・画像などマルチパートデータの参照先の起源
・実行中のスクリプトの起源

以下は実行シナリオとセキュリティポリシーの概要です。

|データの起源  |スクリプトの起源  |適用するルール  |
|---|---|---|
|オンライン  |同一オリジン  |HTMLをそのまま扱う。ローカルファイルにアクセスしない。  |
|オンライン  |別のオリジン  |HTMLをエスケープする。ローカルファイルにアクセスしない。  |
|ローカルアプリ  |任意  |HTMLをそのまま扱う。ローカルファイルにアクセス可能。  |

リッチテキストを貼り付ける際に、script要素やJavaScriptなどの潜在的に問題のあるコンテンツを削除してペーストすることで、セキュリティリスクを緩和することができます。
デフォルトではそのように動作しますが、pasteイベントハンドラはサニタイズされていない元のデータを取得して処理することもできます。

## 11.2 General security policies

実装は、取得した[DataTransferItemList](https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist)に入っていた[ファイル](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-files-2)への参照について、リソースをダウンロードしたり内容を出力したりしてはいけません。

クリップボード上のデータがローカルアプリからのものでない場合、実装は参照されたローカルファイルへのアクセス権を与えてはいけません。
たとえばオンライン由来のデータに`<img src="file://localhost/example.jpg">`と書かれていても、example.jpgのエントリをclipboardData.itemsに追加してはいけません。

## 11.3 Nuisance considerations

スクリプトが[DataTransfer API](https://html.spec.whatwg.org/multipage/dnd.html#datatransfer)を使ってシステムクリップボード上のデータを引っかき回すことによって、ユーザを苛立たせ混乱させる可能性があります。
この仕様書ではそのような迷惑行為を防ぐ手立ては書式化しませんが、実装が独自に制限を追加する可能性はあります(MAY)。

スクリプトが非常に大量のデータをクリップボードに貼り付けようとしていたとしても、実装はその命令をハンドリングする必要があります(MUST)。

# 12 Privacy Considerations

信頼できないスクリプトには、クリップボードへの自由なアクセス許可を与えるべきではありません(SHOULD NOT)。
この仕様では、ユーザが明示的にペースト動作を行った場合には、クリップボードAPIからクリップボードデータへのアクセスが許可されます。
ただし、実装は注意深く行わなければならず、最低限以下の注意事項を守る必要があります(MUST)。

・クリップボードの内容を返す[DataTransfer](https://html.spec.whatwg.org/multipage/dnd.html#datatransfer)オブジェクトは、ClipboardEventイベントハンドラの外部では使用できないようにしなければならない(MUST)。
・スクリプトが[DataTransfer](https://html.spec.whatwg.org/multipage/dnd.html#datatransfer)オブジェクトをClipboardEventイベントハンドラ外で保持するようにしていた場合、全てのメソッドは何もしないようにしなければならない(MUST)。
・クリップボードにアクセスするために、スクリプト自らが合成イベントを作成してはならない(MUST NOT)。
・実装は、ユーザが明示的に許可しない限り`document.execCommand("paste")`を呼び出さないようにすべきである(SHOULD NOT)。

実装は、[DataTransfer](https://html.spec.whatwg.org/multipage/dnd.html#datatransfer)によって提供される機能をさらに制限することができます(MAY)。
たとえばこのAPI自体を無効にしたり、アクセスを許可するWebサイトを設定したりすることができます。


## Appendix A: Algorithms

### write content to the clipboard

クリップボード書き込み処理のアルゴリズム。

入力
・[DataTransferItemList](https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist).itemsのリスト
・"clear-was-called"のフラグ
・"types-to-clear"のリスト

出力
・なし

1 itemsが空ではない場合、
1.1 クリップボードを空にする。
1.2 itemsの各アイテムごとに以下を実行する。
1.2.1 データ型が"text/plain"である場合、
1.2.1.1 OSとロケールの規則に従い、エンコードが正しいことを確認する。
1.2.1.2 プラットフォームの規則に従い、改行コードを整形する。
1.2.1.2 OSのクリップボード書式に従い、テキストをクリップボードにペーストする。
1.2.2 データが[必須データ型](https://www.w3.org/TR/clipboard-apis/#mandatory-data-types)に登録されたものであれば、
1.2.2.1 OSのクリップボード書式に従い、データをクリップボードにペーストする。
1.2.3 データがそれ以外のデータ型の場合
1.2.3.1 実装による。
2 itemsが空である場合、
2.1 "clear-was-called"フラグがtrueである場合、
2.1.1 "types-to-clear"リストが空である場合、
2.1.1.1 クリップボードを空にする。
2.1.2 "types-to-clear"リストが空ではない場合、
2.1.2.1 OSと実装が提供する方法で、クリップボードから"types-to-clear"の対象を削除する。

### fire a clipboard event

クリップボードイベントのアルゴリズム。

入力
・[ClipboardEvent](https://www.w3.org/TR/clipboard-apis/#clipboardevent)イベント

出力
・なし

1 "clear-was-called"フラグをfalseにする。
2 "types-to-clear"リストを空にする。
3 "clipboard-event-data"に[items](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-items-2)が空の[DataTransfer](https://html.spec.whatwg.org/multipage/dnd.html#datatransfer)をセットする。
4 "clipboard-entry"に現在のクリップボードシーケンス番号をセットする。クリップボードシーケンス番号をサポートしていないOSであればnull。
5 イベントがユーザによって発火したものである場合"trusted"にtureを、そうでなければfalseをセットする。
6 以下の手順で"target"を設定する。
6.1 コンテキストが編集可能である場合、
6.1.1 現在選択している要素の開始点を含む要素を"target"にセットする。未選択であれば[body要素](https://html.spec.whatwg.org/multipage/dom.html#the-body-element-2)をセットする。
6.2 コンテキストが編集不可能である場合、
6.2.1 現在選択している要素の開始点を含む要素を"target"にセットする。未選択であれば[body要素](https://html.spec.whatwg.org/multipage/dom.html#the-body-element-2)をセットする。
7 以下の順序でイベントを処理する。
7.1 ClipboardEventが"paste"である場合、
7.1.1 "clipboard-event-data"内の[drag data store mode](https://html.spec.whatwg.org/multipage/dnd.html#drag-data-store-mode)フラグを[read/write](https://html.spec.whatwg.org/multipage/interaction.html#concept-dnd-rw)に設定する。
7.1.2 "trusted"がtrueであるか、実装がスクリプトにクリップボードへのアクセス許可を与えている場合、
7.1.2.1 クリップボード内の各"clipboard-part"について、以下を繰り返し実行する。
7.1.2.1.1 "clipboard-part"にプレーンテキストが含まれているならば、
7.1.2.1.1.1 スクリプトエンジンがテキストのエンコーディングに対応していることを確認する。
7.1.2.1.1.2 新たな[DataTransferItem](https://html.spec.whatwg.org/multipage/dnd.html#datatransferitem)"new-data"を作成し、[drag data item kind](https://html.spec.whatwg.org/multipage/interaction.html#drag-data-item-kind)をstringに、[drag data item type string](https://html.spec.whatwg.org/multipage/interaction.html#drag-data-item-type-string)を"text/plain"にセットする。
7.1.2.1.1.3 "new-data"にプレーンテキストをセットする。
7.1.2.1.1.4 "new-data"を"clipboard-event-data".[items](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-items-2)に追加する。7.1.2.1.2 "clipboard-part"がファイルへの参照であるならば、
7.1.2.1.2.1 参照ファイルのMIME typeを取得する。
7.1.2.1.2.2 新たな[DataTransferItem](https://html.spec.whatwg.org/multipage/dnd.html#datatransferitem)"new-data"を作成し、[drag data item kind](https://html.spec.whatwg.org/multipage/interaction.html#drag-data-item-kind)をfileに、[drag data item type string](https://html.spec.whatwg.org/multipage/interaction.html#drag-data-item-type-string)を該当のMIME typeにセットする。MIME typeが不明であれば"application/octet-stream"をセットする。
7.1.2.1.2.3 "new-data"にファイルへの参照をセットする。
7.1.2.1.2.4 "new-data"を"clipboard-event-data".[items](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-items-2)に追加する。7.1.2.1.3 "clipboard-part"に"HTML-"か"XHTML-"が含まれている場合、
7.1.2.1.3.1 実装がHTML貼り付けをサポートしている場合、[HTMLペーストイベント](https://www.w3.org/TR/clipboard-apis/#process-an-html-paste-event)に従って"clipboard-part"と"clipboard-event-data"のマークアップを処理する。

7.1.2.1.4 "clipboard-part"がそれ以外の[サポートしているデータ型](https://www.w3.org/TR/clipboard-apis/#mandatory-data-types)である場合、
7.1.2.1.4.1 データのMIME typeを取得する。
7.1.2.1.4.2 新たな[DataTransferItem](https://html.spec.whatwg.org/multipage/dnd.html#datatransferitem)"new-data"を作成し、[drag data item kind](https://html.spec.whatwg.org/multipage/interaction.html#drag-data-item-kind)をfileに、[drag data item type string](https://html.spec.whatwg.org/multipage/interaction.html#drag-data-item-type-string)を該当のMIME typeにセットする。
7.1.2.1.1.3 "new-data"に対象のデータをセットする。
7.1.2.1.1.4 "new-data"を"clipboard-event-data".[items](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-items-2)に追加する。7.1.3 "clipboard-event-data".[files](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-files-2)プロパティを、"clipboard-event-data".[items](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-items-2)プロパティと同じになるように更新する。
7.1.4 "clipboard-event-data".[types](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-types-2)プロパティを、"clipboard-event-data".[items](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-items-2)プロパティと同じになるように更新する。
7.2 ClipboardEventが"copy"もしくは"cut"である場合、
7.2.1 対象の[DataTransfer](https://html.spec.whatwg.org/multipage/dnd.html#datatransfer)オブジェクトについて、[drag data store mode](https://html.spec.whatwg.org/multipage/interaction.html#drag-data-store-mode)フラグに[read/write](https://html.spec.whatwg.org/multipage/interaction.html#concept-dnd-rw)をセットする。
8 "clipboard-event-data"に[clipboardData](https://www.w3.org/TR/clipboard-apis/#dom-clipboardevent-clipboarddata)をセットする。
9 "trusted"に[isTrusted](https://dom.spec.whatwg.org/#dom-event-istrusted)をセットする。
10 キャンセル可能な[ClipboardEvent](https://www.w3.org/TR/clipboard-apis/#clipboardevent)イベントeを発行する。

イベントのディスパッチ中にデータにアクセスするための要件は[HTMLLS](https://www.w3.org/TR/clipboard-apis/#biblio-htmlls)で定義されています。


### process an HTML paste event

クリップボード読み込み処理のアルゴリズム。

入力
・"clipboard-part"、処理対象のクリップボード
・"clipboard-event-data"、対象となる[DataTransfer](https://html.spec.whatwg.org/multipage/dnd.html#datatransfer)オブジェクト

出力
・なし

1 新たな[DataTransferItem](https://html.spec.whatwg.org/multipage/dnd.html#datatransferitem)"new-data"を作成し、[drag data item kind](https://html.spec.whatwg.org/multipage/interaction.html#drag-data-item-kind)を"Plain Unicode string"に、[drag data item type string](https://html.spec.whatwg.org/multipage/interaction.html#drag-data-item-type-string)を"text/html"もしくは"application/xhtml+xml"にセットする。
2 "clipboard-part"からマークアップを抽出し、対象のパーサを使用してDOMツリーを構築する。
3 マークアップのソースURLが既知である場合は、hrefおよびsrc属性の全ての相対URLを絶対URLに書き換える。
4 マークアップのオリジンがローカルアプリケーションであった場合、ローカルファイルや他のクリップボードへの参照があるかをチェックする。存在していた場合、[RFC2392](https://www.w3.org/TR/clipboard-apis/#biblio-rfc2392)に従って"content-id"参照へと書き換える。書き換え方法は以下に従う。
4.1 参照しようとしたファイルもしくはクリップボードが"clipboard-event-data".[items](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-items-2)に既に入っている場合、
4.1.1 "itemNumber"を既存エントリのインデックス番号に指定する。
4.2 入っていない場合、
4.2.1 新たな[DataTransferItem](https://html.spec.whatwg.org/multipage/dnd.html#datatransferitem)"new-file-data"を作成し、[drag data item kind](https://html.spec.whatwg.org/multipage/interaction.html#drag-data-item-kind)をfileに、[drag data item type string](https://html.spec.whatwg.org/multipage/interaction.html#drag-data-item-type-string)を該当のMIME typeに、不明であれば"application/octet-stream"にセットする。
4.2.2 新たな[File](https://w3c.github.io/FileAPI/#dfn-file)"file-info"を作成し、[name](https://w3c.github.io/FileAPI/#dfn-name)をHTML属性のnameパートにセットする。[lastModified](https://w3c.github.io/FileAPI/#dfn-lastModified)は参照するファイルの時刻、もしくは参照先がクリップボードであれば0にセットする。
4.2.3 "new-file-data"内の[File](https://w3c.github.io/FileAPI/#dfn-file)オブジェクトに"file-info"をセットする。
4.2.4 "clipboard-event-data".[item](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-items-2)に"new-file-data"をセットし、itemNumberを[DataTransferItemList](https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist)のインデックス番号にする。
4.3 ローカルファイルもしくはクリップボードを参照している部分のDOM属性を、'cid:'+itemNumberに変更する。
5 変更後のDOMをサニタイズし、結果のHTMLを"new-data"にセットする。
6 "clipboard-event-data".[item](https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-items-2)に"new-data"をセットする。


## Conformance

### Document conventions

各キーワード『しなければならない( MUST )』『してはならない( MUST NOT )』『要求されている( REQUIRED )』『することになる( SHALL )』『することはない( SHALL NOT )』『する必要がある( SHOULD )』『しないほうがよい( SHOULD NOT )』『推奨される( RECOMMENDED )』してもよい( MAY )』『選択できる( OPTIONAL )』は[RFC2119](https://www.w3.org/TR/clipboard-apis/#biblio-rfc2119)に従います。
ただ読みやすさを優先し、各単語を大文字表示してはいません。

アルゴリズムの内で表現されている要件("falseを返す"など)は、RFC2119の意味に従います。

### Conformant Algorithms

アルゴリズムおよび各ステップにおいて表示されている要件は、最終的な結果が同じであるかぎり、どのような方法でも実装することができます。
特にこのドキュメントで定義されているアルゴリズムは、流れの理解しやすさを優先しており、そのまま実行されることを意図していません。
従ってアルゴリズムの実装は最適化することが推奨されます。

## References

### Normative References

DOM https://dom.spec.whatwg.org/
ECMASCRIPT https://tc39.github.io/ecma262/
FileAPI https://www.w3.org/TR/FileAPI/
HTML https://html.spec.whatwg.org/multipage/
HTMLLS https://html.spec.whatwg.org/multipage/
RFC2119 https://tools.ietf.org/html/rfc2119
RFC2392 http://www.ietf.org/rfc/rfc2392.txt
WebIDL https://heycam.github.io/webidl/

### Informative References

HTML5 https://www.w3.org/TR/html5/
MICROSOFT-CLIP-OP http://msdn.microsoft.com/en-us/library/ms537658.aspx
SVG11 https://www.w3.org/TR/SVG11/


# 感想

読み取り権限はどう考えても即刻抹殺すべき(MUST)。
百兆歩譲って、あらゆるサイトで一律に完全拒否して許可ダイアログも出さないオプションを用意するのであれば存在することを許そう(SHOULD NOT)。

・どこかの会員制サイトでログインダイアログが表示される
・パスワードマネージャからパスワードをコピーする
・別ウィンドウで別のサイトを閲覧してリンクを踏む

これで死亡だ。
少なくとも私はこの地雷を踏み抜かない自信は無い。
ドラフトでは[アクセス許可](https://github.com/w3c/clipboard-apis/issues/51)などと生温いことを言ってるが、そんなもの誰も読まないことはとっくに証明されている。

あとユーザアクションでしか起動できないと言ってるけど、ユーザアクションが具体的に指しているものがclickなのかinputなのかmouseoverなのかが書かれていない。
万一focusあたりで起動してしまおうものなら『別ウィンドウで別のサイトを閲覧』した時点で死ぬのだがどうか。


Clipboard APIを使わない方法として、本文でも出てきますが`document.execCommand('copy')`というコマンドが存在し、現在選択しているテキストをクリップボードにコピーできます。
というか元々こちらがあって、しかしブラウザごとの互換性がいまいちだったためにこのAPIが策定されたという経緯があります。
そして、クリップボードから読み取りを行う`document.execCommand('paste')`コマンドは、全てのブラウザにおいて[禁止](https://www.fxsitecompat.com/ja/docs/2015/document-execcommand-for-cut-copy-and-paste-no-longer-throws/)されています。
一律禁止することで安全を確保しているわけです。

………………禁止されて[いました](https://developer.mozilla.org/ja/docs/Mozilla/Add-ons/WebExtensions/Interact_with_the_clipboard#Browser-specific_considerations_2)。