Web アプリケーションはどのようにして貼り付けイベントを検出し、貼り付けるデータを取得できるのでしょうか?
テキストをリッチ テキスト エディターに貼り付ける前に、HTML コンテンツを削除したいと思います。
貼り付けた後にテキストをクリーンアップすることはできますが、以前の書式設定がすべて失われるという問題があります。たとえば、エディターで文章を書いて太字にすることはできますが、新しいテキストを貼り付けると、すべての書式設定が失われます。貼り付けたテキストだけをクリーンアップし、以前の書式設定はそのままにしておきたいのです。
理想的には、ソリューションはすべての最新ブラウザ (MSIE、Gecko、Chrome、Safari など) で動作する必要があります。
MSIE には がありますclipboardData.getData()
が、他のブラウザでは同様の機能は見つかりませんでした。
ベストアンサー1
ソリューション 1 (プレーンテキストのみ、Firefox 22 以降が必要)
IE6+、FF 22+、Chrome、Safari、Edge で動作します (IE9+ でのみテストされていますが、それより低いバージョンでも動作するはずです)
HTML の貼り付けまたは Firefox <= 22 のサポートが必要な場合は、ソリューション 2 を参照してください。
function handlePaste(e) {
var clipboardData, pastedData;
// Stop data actually being pasted into div
e.stopPropagation();
e.preventDefault();
// Get pasted data via clipboard API
clipboardData = e.clipboardData || window.clipboardData;
pastedData = clipboardData.getData('Text');
// Do whatever with pasteddata
alert(pastedData);
}
document.getElementById('editableDiv').addEventListener('paste', handlePaste);
<div id='editableDiv' contenteditable='true'>Paste</div>
このソリューションでは、関数に非標準のパラメータ「Text」を使用していることに注意してくださいgetData
。ただし、執筆時点ではすべてのブラウザで動作します。
ソリューション 2 (HTML、Firefox <= 22 で動作)
IE6+、FF 3.5+、Chrome、Safari、Edgeでテスト済み
var editableDiv = document.getElementById('editableDiv');
function handlepaste(e) {
var types, pastedData, savedContent;
// Browsers that support the 'text/html' type in the Clipboard API (Chrome, Firefox 22+)
if (e && e.clipboardData && e.clipboardData.types && e.clipboardData.getData) {
// Check for 'text/html' in types list. See abligh's answer below for deatils on
// why the DOMStringList bit is needed. We cannot fall back to 'text/plain' as
// Safari/Edge don't advertise HTML data even if it is available
types = e.clipboardData.types;
if (((types instanceof DOMStringList) && types.contains("text/html")) || (types.indexOf && types.indexOf('text/html') !== -1)) {
// Extract data and pass it to callback
pastedData = e.clipboardData.getData('text/html');
processPaste(editableDiv, pastedData);
// Stop the data from actually being pasted
e.stopPropagation();
e.preventDefault();
return false;
}
}
// Everything else: Move existing element contents to a DocumentFragment for safekeeping
savedContent = document.createDocumentFragment();
while (editableDiv.childNodes.length > 0) {
savedContent.appendChild(editableDiv.childNodes[0]);
}
// Then wait for browser to paste content into it and cleanup
waitForPastedData(editableDiv, savedContent);
return true;
}
function waitForPastedData(elem, savedContent) {
// If data has been processes by browser, process it
if (elem.childNodes && elem.childNodes.length > 0) {
// Retrieve pasted content via innerHTML
// (Alternatively loop through elem.childNodes or elem.getElementsByTagName here)
var pastedData = elem.innerHTML;
// Restore saved content
elem.innerHTML = "";
elem.appendChild(savedContent);
// Call callback
processPaste(elem, pastedData);
}
// Else wait 20ms and try again
else {
setTimeout(function() {
waitForPastedData(elem, savedContent)
}, 20);
}
}
function processPaste(elem, pastedData) {
// Do whatever with gathered data;
alert(pastedData);
elem.focus();
}
// Modern browsers. Note: 3rd argument is required for Firefox <= 6
if (editableDiv.addEventListener) {
editableDiv.addEventListener('paste', handlepaste, false);
}
// IE <= 8
else {
editableDiv.attachEvent('onpaste', handlepaste);
}
<div id='div' contenteditable='true'>Paste</div>
説明
onpaste
のイベントにはdiv
関数handlePaste
がアタッチされており、貼り付けイベントのオブジェクトという単一の引数が渡されますevent
。特に興味深いのは、clipboardData
IE 以外のブラウザでクリップボードへのアクセスを可能にするこのイベントのプロパティです。IE では同等のものは ですwindow.clipboardData
が、これは API が若干異なります。
以下のリソースセクションを参照してください。
関数handlepaste
:
この機能には 2 つのブランチがあります。
最初は の存在を確認しevent.clipboardData
、そのtypes
プロパティに 'text/html' (メソッドを使用して確認される、または メソッドを使用して確認される文字列のtypes
いずれか) が含まれているかどうかを確認します。これらの条件がすべて満たされている場合は、ソリューション 1 と同様に進めますが、'text/plain' の代わりに 'text/html' を使用します。これは現在、Chrome および Firefox 22 以降で動作します。DOMStringList
contains
indexOf
この方法がサポートされていない場合(他のすべてのブラウザ)、
- 要素の内容を
DocumentFragment
- 要素を空にする
waitForPastedData
関数を呼び出す
関数waitforpastedata
:
この関数は、最初に貼り付けられたデータをポーリングします (20 ミリ秒ごとに 1 回)。これは、データがすぐに表示されないために必要です。データが表示されると、次の処理が実行されます。
- 編集可能なdivのinnerHTML(貼り付けられたデータ)を変数に保存します。
- DocumentFragmentに保存されたコンテンツを復元します
- 取得したデータを使用して「processPaste」関数を呼び出します
関数processpaste
:
貼り付けたデータに対して任意の処理を行います。この場合は、データに警告を出すだけなので、好きなように操作できます。貼り付けたデータに対して、何らかのデータ サニタイズ プロセスを実行する必要があるかもしれません。
カーソル位置の保存と復元
実際の状況では、選択内容を事前に保存し、後で復元したいと考えるでしょう(contentEditable <div> にカーソル位置を設定する)。その後、ユーザーが貼り付け操作を開始したときにカーソルがあった位置に、貼り付けたデータを挿入できます。
MDN のリソース
感謝ティム・ダウンDocumentFragmentの使用を提案し、clipboardData.typesの文字列の代わりにDOMStringListを使用したためにFirefoxでエラーをキャッチできるようにしました。