ブックマークレット
私は、以下のブックマークレットを使用している。
これは、開いているページのタイトルとURLをコピーする用に入れたテキストボックスを新しいタブで表示し、コピーしてSNSなどで共有しやすくするためのものである。
javascript:window.open().document.write(
'<input%20type=\x22text\x22%20onclick=\x22select();\x22%20value=\x22'+
document.title.replace(/\x26/g,'\x26amp;').replace(/\x22/g,'\x26#34;')+'%20'+
location.href.replace(/\x26/g,'\x26amp;').replace(/\x22/g,'\x26#34;')+'\x22>'
)
いつから使っているかはわからないが、だいぶ前な気がする。
効かない事例
さて、ある日、このブックマークレットをYouTubeで用いたところ、新しいタブは開いたが、テキストボックスが表示されなかった。
開発者ツールのコンソールを見ると、以下のエラーが出ていた。
Uncaught TypeError: Document.write: Sink type mismatch violation blocked by CSP
AIで殴る
よくわからないので、とりあえず Perplexity にエラーメッセージをコピペして、直し方を聞いてみた。
> Uncaught TypeError: Document.write: Sink type mismatch violation blocked by CSP
直し方おしえろください
> Uncaught TypeError: Document.write: Sink type mismatch violation blocked by...
その結果、document.write のかわりにDOM操作を用いることで、回避できる可能性が示された。
DOM操作に置き換える
冒頭のブックマークレットをいつ作ったかは定かではないが、おそらく古い技術で作られたものだろう。
今の知識に基づいて書き直してみた。
javascript:window.open().document.body.appendChild(
(() => {
const i = document.createElement('input');
i.type = 'text';
i.value = document.title + ' ' + location.href;
i.addEventListener('click',(e) => e.target.select());
return i;
})()
)
javascript:window.open().document.body.appendChild((()=>{const i=document.createElement('input');i.type='text';i.value=document.title+' '+location.href;i.addEventListener('click',(e)=>e.target.select());return i;})())
結果は成功。
以前のブックマークレットでテキストボックスが出なかったYouTubeでも、テキストボックスを出すことができた。
さらに、以前のブックマークレットではテキストボックスは出せてもフォーカス時に自動で中身を選択する機能が動かないサイトもあったが、そのようなサイトでも新しいブックマークレットで出したテキストボックスでは自動選択が動作するようだった。
さらに、以前のブックマークレットでは & や " を手動でエスケープしていたが、新ブックマークレットではエスケープせずにそのまま属性に代入するだけになり、コードがスッキリした。
おわりに
ブックマークレットで用いている document.write が動かないサイトがあることを発見し、AI に対処方法を聞いたところ「かわりに通常のDOM操作を用いるとよい」という回答を得たので、その通りにすることで動作が改善した事例を紹介した。
今回の記事はあくまで「今回のケースにおいては、こうすると問題が解決した」という事例の紹介であり、常にこれが良い対処法であることは保証しない。
また、将来のWebブラウザなどの仕様変更により、今回の対策が使えなくなってしまう可能性もないとはいえない。
今回の情報を利用するかどうかの判断、および利用は自己責任で行うこと。