Solution #1 (Plain Text only and requires Firefox 22+)
Works for IE6+, FF 22+, Chrome, Safari, Edge
(Only tested in IE9+, but should work for lower versions)
If you need support for pasting HTML or Firefox <= 22, see Solution #2.
HTML
<div id='editableDiv' contenteditable='true'>Paste</div>
JavaScript
function handlePaste (e) {
var clipboardData, pastedData;
e.stopPropagation();
e.preventDefault();
clipboardData = e.clipboardData || window.clipboardData;
pastedData = clipboardData.getData('Text');
alert(pastedData);
}
document.getElementById('editableDiv').addEventListener('paste', handlePaste);
JSFiddle: https://jsfiddle.net/swL8ftLs/12/
Note that this solution uses the parameter 'Text' for the getData
function, which is non-standard. However, it works in all browsers at the time of writing.
Solution #2 (HTML and works for Firefox <= 22)
Tested in IE6+, FF 3.5+, Chrome, Safari, Edge
HTML
<div id='div' contenteditable='true'>Paste</div>
JavaScript
var editableDiv = document.getElementById('editableDiv');
function handlepaste (e) {
var types, pastedData, savedContent;
if (e && e.clipboardData && e.clipboardData.types && e.clipboardData.getData) {
types = e.clipboardData.types;
if (((types instanceof DOMStringList) && types.contains("text/html")) || (types.indexOf && types.indexOf('text/html') !== -1)) {
pastedData = e.clipboardData.getData('text/html');
processPaste(editableDiv, pastedData);
e.stopPropagation();
e.preventDefault();
return false;
}
}
savedContent = document.createDocumentFragment();
while(editableDiv.childNodes.length > 0) {
savedContent.appendChild(editableDiv.childNodes[0]);
}
waitForPastedData(editableDiv, savedContent);
return true;
}
function waitForPastedData (elem, savedContent) {
if (elem.childNodes && elem.childNodes.length > 0) {
var pastedData = elem.innerHTML;
elem.innerHTML = "";
elem.appendChild(savedContent);
processPaste(elem, pastedData);
}
else {
setTimeout(function () {
waitForPastedData(elem, savedContent)
}, 20);
}
}
function processPaste (elem, pastedData) {
alert(pastedData);
elem.focus();
}
if (editableDiv.addEventListener) {
editableDiv.addEventListener('paste', handlepaste, false);
}
else {
editableDiv.attachEvent('onpaste', handlepaste);
}
JSFiddle: https://jsfiddle.net/nicoburns/wrqmuabo/23/
Explanation
The onpaste
event of the div
has the handlePaste
function attached to it and passed a single argument: the event
object for the paste event. Of particular interest to us is the clipboardData
property of this event which enables clipboard access in non-ie browsers. In IE the equivalent is window.clipboardData
, although this has a slightly different API.
See resources section below.
The handlepaste
function:
This function has two branches.
The first checks for the existence of event.clipboardData
and checks whether it's types
property contains 'text/html' (types
may be either a DOMStringList
which is checked using the contains
method, or a string which is checked using the indexOf
method). If all of these conditions are fulfilled, then we proceed as in solution #1, except with 'text/html' instead of 'text/plain'. This currently works in Chrome and Firefox 22+.
If this method is not supported (all other browsers), then we
- Save the element's contents to a
DocumentFragment
- Empty the element
- Call the
waitForPastedData
function
The waitforpastedata
function:
This function first polls for the pasted data (once per 20ms), which is necessary because it doesn't appear straight away. When the data has appeared it:
- Saves the innerHTML of the editable div (which is now the pasted data) to a variable
- Restores the content saved in the DocumentFragment
- Calls the 'processPaste' function with the retrieved data
The processpaste
function:
Does arbitrary things with the pasted data. In this case we just alert the data, you can do whatever you like. You will probably want to run the pasted data through some kind of data sanitising process.
Saving and restoring the cursor position
In a real sitution you would probably want to save the selection before, and restore it afterwards (Set cursor position on contentEditable <div>). You could then insert the pasted data at the position the cursor was in when the user initiated the paste action.
Resources:
Thanks to Tim Down to suggesting the use of a DocumentFragment, and abligh for catching an error in Firefox due to the use of DOMStringList instead of a string for clipboardData.types
event.clipboardData.getData('Text')
worked for me. – Andre Elricodocument.addEventListener('paste'...
worked for me but caused conflicts if a user wanted to be able to paste elsewhere on the page. Then I triedmyCanvasElement.addEventListener('paste'...
, but that didn't work. Eventually I figured outmyCanvasElement.parentElement.addEventListener('paste'...
worked. – Ryan