PrsPrsBK’s blog

Princess Princess Burn Knuckle

WebExtensions: 指定した文字列をクリップボードに格納する (コピーする)

概要

Firefox の自分用アドオンで、特定のウェブページを見ているときに、その一部から文字列を構成してクリップボードに格納したい。Content scripts で copy イベントのリスナを使った話。

追記: mdn/webextensions-examples の見てなかった方に例があるのでそちらを見ればよく、このブログは読まなくてよい。

1. manifest.json の permissions に "clipboardWrite" を指定する。2. document.addEventListener('copy', onCopy); とする。3.(以下 onCopy の話) copy イベントから DataTransfer オブジェクトを取得する。4. setData()クリップボードに文字列を格納する。

Firefox Developer Edition 54 と 57。なんとなく Google Chrome も試した。

やった

document.execCommand() でやれと述べられるができなかった

見ているウェブページの一部から文字列を構成してクリップボードに格納したい。文字列は選択せずに都合のよいように作りたい。

MDN: Addons: Browser Extensions にニーズそのものである Interact with the clipboard がある。document.execCommand("copy") しろというが、これは文字列を選択しないとコピーできない (ドキュメント)。github mdn/webextensions-examples の selection-to-clipboard もこれを使っている。

WebExtensions 以前はどうやったか。古い話だが、Add-on SDK には clipboard API があり、var clipboard = require('sdk/clipboard'); で利用できた。Comparison with the Add-on SDKAPI 比較対照資料にこう書いてある。

document.execCommand without using select() and similar in the background page.

しかしできない。document.execCommand('copy', false, some_text) とやったができなかった。ほしい文字列 (HTML には存在しない) を選択していることにできればいいが、window.setSelection(任意の文字列) はあるはずがない。

copy イベント経由でデータをセットする

npm モジュールにクリップボードとやり取りするものがあるだろうから (探していない)、それを webpack でバンドルして利用すればできるに決まっている。もっと言えばアドオンでやる必要はない。でもウェブページを見ながらブラウザ上でそのままやりたいしモジュールバンドルはもっとモジュールが明らかに必要な時にやる、ということで情報を探した。

結果 copy イベントがあると判ったので、Ctrl-C でコピーが発生したときのイベントリスナで処理させることにした。

document.addEventListener('copy', onCopy); して次のようにした。できた。

function onCopy(ev) {
  //実際に何か選択してるときは動作させたくない
  if(window.getSelection().toString() === '') {
    //雑に作ったので構成した文字列をグローバル変数に収めている。あとで直せばいい
    setTextForCopy(); //HTML を解析して文字列を作って TO_CLIPBOARD に格納する
    if(TO_CLIPBOARD !== '') {
      ev.preventDefault();
      let transfer = ev.clipboardData;
      transfer.setData('text/plain', TO_CLIPBOARD);
      TO_CLIPBOARD = '';
    }
  }
}
document.addEventListener('copy', onCopy);

Ctrl-C ではなく Ctrl-Y 等別のキーでやりたいときはキー押し下げで document.execCommand("copy") でコピーを発生させればいいけど、このままでは何か選択してたらそれが Ctrl+Y でクリップボードにコピーされてしまう。まあいいか。

なお、Firefox ではなく Google Chrome にローカルフォルダからインストールして使っても動作した。Google Chrome は開発版のリロードが楽でいいですね、という感想を持った。