3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ブックマークレットで発生するClipboard APIの "Document is not focused." をなんとかする

Last updated at Posted at 2024-04-09

久々にまともなやつ。

やること

  • JavaScriptで何かしらの情報をクリップボードへコピーするブックマークレットを作る

道具

  • Clipboard API

背景

昔は、document.execCommand("copy"); というコードがありました。
ただ、こいつ今は非推奨なんですよね……

で、代わりになるClipboard APIという便利なAPIが登場しました。
登場からもうかれこれ5年以上は経過しているはず[未確認]で、最初は対応していないブラウザも多く、まだまだexecCommand()が使われていましたが、現在はもう(基本機能は)だいたいのブラウザで使えるはずです。

しかし、新しいAPIはとてもしっかりものなので、セキュリティがガッチリしているんですよね。は~~~面倒~~~

例えば、デベロッパツールでコンソールを開いて、次のようなexecCommand()を使用したコードを実行してみます。
開いているページのURLをクリップボードにコピーするコードです。

useExecCommand.js
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を使うとどうなるか。こんな感じです。

useClipboardAPI.js
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の実行を少し遅らせるだけで大丈夫なんだそう。何で???

delayedExecAPI.js
setTimeout(() => navigator.clipboard.writeText(location.href), 500);  // 500ms遅らせて実行

何で?って書きましたが、答えは先人↓が調査してくれています。つまり丸パクリです。

こういうのをGoogle検索くんには出してほしいんですよ。無価値なまとめサイトと広告サイトをトップに持ってくるな。

デベロッパツールでは相変わらず「フォーカスが当たってねえよ!」って怒られますが、ブックマークレットではちゃんと動いてくれます。

これで非推奨のexecCommand()くんとさよならできます。R.I.P.

おまけ

自分で作ったブックマークレットです。開いているページのURLとページタイトルを、[ページタイトル], [URL]のフォーマットでクリップボードにコピーしてくれます。引用情報として利用するときに便利!

copyTitleAndUrl.js
// URLとタイトルを連結
var copyText = `${document.title}, ${location.href}`;

// クリップボードにコピー
setTimeout(() => navigator.clipboard.writeText(copyText), 500);

// コピーしたことをアラートで表示
alert(`Copied to clipboard:\n${copyText}`);

コンパイル後のコードは↓

compiledCode.js
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

なおドメインごとに、このブックマークレットを実行する際に、下図のようなクリップボードへのコピーを許可するか確認するダイアログが表示されます。これもセキュリティ対策ですね、しっかりしてらぁ。

2024-04-09_12h59_18.jpg

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?