久々にまともなやつ。
やること
- JavaScriptで何かしらの情報をクリップボードへコピーするブックマークレットを作る
道具
- Clipboard API
背景
昔は、document.execCommand("copy");
というコードがありました。
ただ、こいつ今は非推奨なんですよね……
で、代わりになるClipboard APIという便利なAPIが登場しました。
登場からもうかれこれ5年以上は経過しているはず[未確認]で、最初は対応していないブラウザも多く、まだまだexecCommand()
が使われていましたが、現在はもう(基本機能は)だいたいのブラウザで使えるはずです。
しかし、新しいAPIはとてもしっかりものなので、セキュリティがガッチリしているんですよね。は~~~面倒~~~
例えば、デベロッパツールでコンソールを開いて、次のようなexecCommand()
を使用したコードを実行してみます。
開いているページのURLをクリップボードにコピーするコードです。
textBox = document.createElement("textarea");
textBox.setAttribute("id", "target");
textBox.setAttribute("type", "hidden");
textBox.textContent = location.href;
document.body.appendChild(textBox);
textBox.select();
document.execCommand("copy"); // ここでクリップボードにコピー
document.body.removeChild(textBox);
ちょっと長いですが、これでクリップボードにURLをコピーできます。
古き良き、って感じです。
では、これをClipboard APIを使うとどうなるか。こんな感じです。
navigator.clipboard.writeText(location.href);
い、1行?????
かがくの ちからって すげー!▼
……が、そうは問屋が卸しません。
このコードを実行すると無慈悲にもエラーが発生します。
Uncaught (in promise) DOMException:
Failed to execute 'writeText' on 'Clipboard': Document is not focused.
Clipboard APIではユーザが明示的にコピーを指示するなど、ドキュメント自身にフォーカスが当たっていないとエラーが返ります。
デベロッパツールでこのコードを実行したとき、フォーカスはデベロッパツールに当たっているのであり、ドキュメントには当たっていない、という判断です。は~~~融通効かね~~~
ここまで簡単のためデベロッパツールで実験しましたが、当然このコードをブックマークレットに落とし込んでも同じエラーが発生します。
ブックマークレットでこの問題を解決するにはどうしたら良いでしょう?
解決したい問題
ブックマークレット上でClipboard APIを使うとき、ドキュメントにフォーカスが当たらない問題を解決するには?
答え
すごく単純で、Clipboard APIの実行を少し遅らせるだけで大丈夫なんだそう。何で???
setTimeout(() => navigator.clipboard.writeText(location.href), 500); // 500ms遅らせて実行
何で?って書きましたが、答えは先人↓が調査してくれています。つまり丸パクリです。
こういうのをGoogle検索くんには出してほしいんですよ。無価値なまとめサイトと広告サイトをトップに持ってくるな。
デベロッパツールでは相変わらず「フォーカスが当たってねえよ!」って怒られますが、ブックマークレットではちゃんと動いてくれます。
これで非推奨のexecCommand()
くんとさよならできます。R.I.P.
おまけ
自分で作ったブックマークレットです。開いているページのURLとページタイトルを、[ページタイトル], [URL]
のフォーマットでクリップボードにコピーしてくれます。引用情報として利用するときに便利!
// URLとタイトルを連結
var copyText = `${document.title}, ${location.href}`;
// クリップボードにコピー
setTimeout(() => navigator.clipboard.writeText(copyText), 500);
// コピーしたことをアラートで表示
alert(`Copied to clipboard:\n${copyText}`);
コンパイル後のコードは↓
javascript:var a=`${document.title}, ${location.href}`;setTimeout(()=>navigator.clipboard.writeText(a),500);alert(`Copied to clipboard:\n${a}`);
ブックマークレット作成のおとも↓
ちなみに、今回のブックマークレットで↓のような文字列をクリップボードにコピーできます。
ブックマークレットで発生するClipboard APIの "Document is not focused." をなんとかする #JavaScript - Qiita, https://qiita.com/kuroan/items/0d1e0d7dd0abfe57ce9a
なおドメインごとに、このブックマークレットを実行する際に、下図のようなクリップボードへのコピーを許可するか確認するダイアログが表示されます。これもセキュリティ対策ですね、しっかりしてらぁ。