クリップボードとのやりとり
拡張機能でクリップボードを操作するには、Web API の navigator.clipboard メソッドと、"clipboardRead" または "clipboardWrite" の拡張機能権限を使用します。navigator.clipboard を使用することで、拡張機能はクリップボードから任意のデータを読み取ったり、クリップボードに任意のデータを書き込んだりすることができます。
メモ:
クリップボード機能を提供するために、Web API の document.execCommand メソッドが使用されていました。しかし、document.execCommand("copy")、document.execCommand("cut")、document.execCommand("paste") はいずれも非推奨となっており、どのブラウザーにおいても動作や利用が保証されなくなりました。これらの機能は、歴史的な参照としてこの記事に記載されています。
navigator.clipboard API は、次の目的のメソッドを提供しています。
- テキストを扱う場合は
navigator.clipboard.readText()とnavigator.clipboard.writeText()が使えます。 - 画像、リッチテキスト、HTML、その他のリッチコンテンツを扱う場合は
navigator.clipboard.read()とnavigator.clipboard.write()が使えます。
メモ:
クリップボード API の書き込みおよび読み取りメソッドは、保護されたコンテキストでのみ利用可能です。拡張機能は、http: ページで動作しているコンテンツスクリプトからはこれらのメソッドを使用することはできません。https: ページからのみ使用することができます。
クリップボードへの書き込み
クリップボード API の navigator.clipboard.write() および navigator.clipboard.writeText() メソッドは、任意のコンテンツをクリップボードに書き込みます。これらのメソッドは保護されたコンテキストから利用できるのですが、拡張機能のユーザーが一時的な有効化を実行した後にのみ機能します。ただし、"clipboardWrite" 権限がある場合は、一時的な有効化は要求されません。
メモ:
Firefox および Chrome では、"clipboardWrite" 権限により、すべての拡張機能コンテキストおよびコンテンツスクリプトからクリップボードへ書き込むことができます。Safari では、"clipboardWrite" 権限は拡張機能コンテキストでのみ対応しています(コンテンツスクリプトでは対応していません)。
この関数は、文字列を受け取り、それをクリップボードに書き込みます。
function updateClipboard(newClip) {
navigator.clipboard.writeText(newClip).then(
() => {
/* クリップボードの設定に成功 */
},
() => {
/* クリップボードの書き込みに失敗 */
},
);
}
execCommand() を使用する
メモ:
document.execCommand("copy") と document.execCommand("cut") は非推奨となっており、どのブラウザーにおいても動作するかどうかや利用できるかどうかが保証されなくなりました。
document.execCommand() メソッドの "cut" と "copy" コマンドは、クリップボードの内容を選択した素材に置き換えるために使用されます。拡張機能は、ユーザーの操作によって発生する短命なイベントハンドラー(例えば、クリックハンドラーなど)において、特別な権限を必要とせずにこれらのコマンドを使用することができます。
例えば、この HTML を含むポップアップがあったとします。
<input id="input" type="text" /> <button id="copy">Copy</button>
"copy" ボタンで <input> 要素の内容をコピーさせるには、次のようなコードを使用します。
function copy() {
let copyText = document.querySelector("#input");
copyText.select();
document.execCommand("copy");
}
document.querySelector("#copy").addEventListener("click", copy);
execCommand() の呼び出しはクリックイベントハンドラー内で行われるため、この拡張機能には特別な権限は必要ありません。
しかし、拡張機能がアラームをきっかけにコピーを開始する場合を例に挙げてみましょう。
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 の navigator.clipboard.read() と navigator.clipboard.readText() メソッドを使うと、保護されたコンテキストでクリップボードから任意のテキストまたはバイナリーデータを読み取ることができます。これにより、編集可能な要素に貼り付けることなく、クリップボードのデータにアクセスすることができます。
これらのメソッドは保護されたコンテキストから利用できるのですが、拡張機能のユーザーが 一時的な有効化を実行し、一時的なコンテキストメニュー内の貼り付けプロンプトをクリックした後にのみ機能します。ただし、"clipboardRead" 権限があれば、ユーザーの確認や一時的な有効化なしに、拡張機能からクリップボードを読み取ることができます。
メモ:
Firefox および Chrome では、"clipboardRead" 権限を有効にすると、すべての拡張機能コンテキストおよびコンテンツスクリプトからクリップボードへの書き込みをすることができます。Safari では、"clipboardRead" 権限は対応していません。
このコードスニペットは、クリップボードからテキストを取得し、ID が "outbox"の要素の内容をそのテキストに置き換えます。
navigator.clipboard
.readText()
.then((clipText) => (document.getElementById("outbox").innerText = clipText));
execCommand() の使用
メモ:
document.execCommand("paste") は非推奨となっており、どのブラウザーにおいても動作するかどうかや利用できるかどうかが保証されなくなりました。
document.execCommand("paste") を使用するには、拡張機能には "clipboardRead" 権限が必要です。この要件は、click や keypress などのユーザーが生成したイベントハンドラーから "paste" コマンドを使用する場合でも存在します。
これを含む HTML を考えてみましょう。
<textarea id="output"></textarea> <button id="paste">Paste</button>
ユーザーが "paste" の <button> をクリックしたときに、クリップボードから ID が "output" の <textarea> 要素の内容を設定するには、次のようなコードを使用します。
function paste() {
let pasteText = document.querySelector("#output");
pasteText.focus();
document.execCommand("paste");
console.log(pasteText.textContent);
}
document.querySelector("#paste").addEventListener("click", paste);
特定のブラウザーにおける留意事項
Chrome の場合:
-
Chrome は拡張機能のサービスワーカーに対して
navigator.clipboardを公開しておらず、また、API の文書フォーカス要件により、オフスクリーン文書からはnavigator.clipboardにアクセスできません。その結果、Chrome 拡張機能では、オフスクリーン文書内で非推奨となったdocument.execCommand()API を使用するか、コンテンツスクリプトや拡張機能ページなど、別のコンテキストでnavigator.clipboardを使用する必要があります。 ページスクリプトの場合、Web API のnavigator.permissionsを使用して"clipboard-write"パーミッションを要求する必要があります。そのパーミッションは、navigator.permissions.query()を使って確認することができます。jsnavigator.permissions.query({ name: "clipboard-write" }).then((result) => { if (result.state === "granted" || result.state === "prompt") { /* クリップボードに書き込む */ } });メモ:
clipboard-write権限は Firefox や Safari では対応していません。
Firefox の場合:
- 貼り付けプロンプトに対するユーザーのレスポンスにおいて、クリップボード API の読み取りメソッドが利用できる機能は、Firefox 127 のウェブページおよび Firefox 147 の拡張機能で導入されました。それ以前は、
"clipboardRead"権限が設定されている場合にのみ、これらのメソッドを利用することができました。
Safari の場合:
"clipboardWrite"権限は、拡張機能のコンテキスト(コンテンツスクリプトを除く)でのみ対応しています。"clipboardRead"権限には対応していません。