JavaScript で paste イベントを活用して画像、ファイル、HTML をブラウザに貼り付ける
paste イベントを活用して画像やファイル、HTML 等さまざまな貼り付けられた情報を簡単に JavaScript で利用する方法を紹介します。
やりたいこと
Web ページを HTML として <input type="text">
や <textarea>
に貼り付け、スクレイピングのように構造を解析して必要なデータだけ取り出すといったことがしたかったのですが、<input type="text">
や <textarea>
は Web ページをコピーして貼り付けるとプレーンテキストとなり文書構造やスタイル情報は落とされてしまいます。コピー&ペーストで HTML の情報を落とさず取得する方法はないかと色々試した中で paste イベントの活用が最も使いやすいと思ったので紹介します。
他に HTML 要素の contenteditable
属性(contenteditable - HTML: ハイパーテキストマークアップ言語 | MDN)や クリップボード API(Clipboard - Web API | MDN)も考えたのですが、前者は今回の目的だけだと使えそうではあったのですが、ファイルが取り扱えなかったので見送り、後者は https 環境が求められるので見送りました。
環境
- ブラウザ
- Microsoft Edge 121.0.2277.112
paste イベント
paste
イベントは、ユーザーがブラウザーのユーザーインターフェイスで「貼り付け」操作を行ったときに発生します。
カーソルが編集可能なコンテキストにある場合(<textarea>
やcontenteditable
属性がtrue
の要素など)、既定のアクションはクリップボードの内容を文書のカーソル位置に挿入します。
- Element: paste イベント - Web API | MDN
さっそくやってみましょう。
適当な画像ファイルをクリップボードにコピーした状態で、この HTML をブラウザで開いて <textarea>
に貼り付けてみます。ブラウザ開発者ツールのコンソールを見てみると ClipBoardEvent
(ClipboardEvent - Web API | MDN) が表示されています。
ClipboardEvent
は他のイベントにはない clipboardData
(ClipboardEvent: clipboardData プロパティ - Web API | MDN)というプロパティーを持っています。
clipboardData
プロパティーは DataTransfer
(DataTransfer - Web API | MDN)オブジェクトとなっていて、items
というプロパティーに貼り付けされた項目が DataTransferItem
(DataTransferItem - Web API | MDN)オブジェクトとして配列ライクに格納されています。
DataTransferItem
は貼り付けられた内容の形式(通常は MIME タイプ)単位に作成されるので注意です。例えば Web ページをコピーして貼り付けた場合は、text/plain
と text/html
の 2 つの MIME タイプを有するため、clipboardData.items.length
は 2
になります。また、画像も Word や PowerPoint から貼り付けると、image/svg+xml
、 image/png
のように 2 つの MIME タイプを持つため、同様に clipboardData.items.length
は 2
になります。
貼り付けられたものの MIME タイプを確認
ここまでのところを実際に確認してみましょう。
ブラウザで開いて <textarea>
に様々なものをペーストしてみてください。コンソールで貼り付けたものの MIME タイプが確認できると思います。
なお、先ほど clipboardData.items
は DataTransferItem
オブジェクトの配列ライクと説明しましたが、インデックス番号の添え字で要素にアクセスしたりはできるのですが、forEach()
のような Array.prototype
が提供しているメソッドは使えません。従ってここでは Array.from()
で一旦 Array
にしてから forEach()
でループしています。
貼り付けられたコンテンツを取得
ではいよいよペーストされた内容を取り出していきましょう。
先ほどは DataTransferItem.type
で MIME タイプを確認しましたがが、別途 DataTransferItem.kind
というプロパティーがあり、string
か file
のどちらかが入ります。DataTransferItem.kind
が string
か file
によって利用するメソッドが異なってきます。
文字列として取得
DataTransferItem.kind
が string
の場合は、DataTransferItem.getAsString()
メソッドを使用します。
DataTransferItem.getAsString()
メソッドは、項目のkind
が プレーン Unicode 文字列 (すなわちkind
がstring
)である場合に、ドラッグデータ項目の文字列データを引数に指定してコールバックを呼び出すメソッドです。
** 構文 **
やってみましょう。
ブラウザで開いて <textarea>
に Web ページをコピーして貼り付けてみてください。<textarea>
にはプレーンテキストしか貼り付けられていませんが、ブラウザ開発者ツールのコンソールには HTML タグ込みで出力されています。
HTML 構造ごと貼り付けたデータを取得できれば以下のようにスクレイピングの要領で構造を解析して必要なデータを取得するといったことも可能です。
見たところインラインスクリプト等は落とされているように見えますが、クロスサイトスクリプティングにならないように貼り付けられた HTML をそのままレンダリングすることは避けた方がよいでしょう。
ファイルとして取得
DataTransferItem.kind
が file
の場合は、DataTransferItem.getAsFile()
で File
(File - Web API | MDN)オブジェクトとして取得します。
アイテムがファイルの場合、
DataTransferItem.getAsFile()
メソッドはドラッグデータ項目の File オブジェクトを返します。項目がファイルでない場合、このメソッドはnull
を返します。
構文返値
File
ドラッグデータ項目がファイルである場合、File
オブジェクトが返されます。それ以外の場合はnull
が返されます。
- DataTransferItem.getAsFile() - Web API | MDN
getAsString()
がコールバックスタイルなのに対して getAsFile()
は普通に返値として File
オブジェクトが返ってきます。
こちらもやってみます。<img>
タグを追加し、画像をコピーするとその画像を img
要素に表示させるようにします。
ブラウザで開いて <textarea>
に PNG 形式の画像を貼りつけてみてください。<img>
要素に表示されると思います。
DataTransferItem.getAsFile()
は File
オブジェクトで返ってくるので FileReader
で読み取ったりと使い道は色々考えられると思います。
あとがき
paste イベントを使って様々なコンテンツを張り付ける方法を紹介しました。クリップボード内の更新とかをしようとするとクリップボード API を使うしかないですが、張り付けたデータをあれこれしたいだけであれば、paste イベントを使ったほうが簡単に扱えるのでよいなと思いました。