Solución n. ° 1 (solo texto sin formato y requiere Firefox 22+)
Funciona para IE6 +, FF 22+, Chrome, Safari, Edge (solo probado en IE9 +, pero debería funcionar para versiones inferiores)
Si necesita soporte para pegar HTML o Firefox <= 22, consulte la Solución # 2.
HTML
<div id='editableDiv' contenteditable='true'>Paste</div>
JavaScript
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);
JSFiddle: https://jsfiddle.net/swL8ftLs/12/
Tenga en cuenta que esta solución utiliza el parámetro 'Texto' para la getData
función, que no es estándar. Sin embargo, funciona en todos los navegadores al momento de escribir.
Solución n. ° 2 (HTML y funciona para Firefox <= 22)
Probado en 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;
// 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);
}
JSFiddle: https://jsfiddle.net/nicoburns/wrqmuabo/23/
Explicación
El onpaste
evento del div
tiene la handlePaste
función adjunta y pasó un único argumento: el event
objeto para el evento de pegar. De particular interés para nosotros es la clipboardData
propiedad de este evento que permite el acceso al portapapeles en navegadores que no sean. En IE, el equivalente es window.clipboardData
, aunque tiene una API ligeramente diferente.
Vea la sección de recursos a continuación.
La handlepaste
función:
Esta función tiene dos ramas.
La primera verifica la existencia de event.clipboardData
y verifica si su types
propiedad contiene 'text / html' ( types
puede ser una DOMStringList
que se verifica usando elcontains
método o una cadena que se verifica con elindexOf
método). Si se cumplen todas estas condiciones, entonces procedemos como en la solución # 1, excepto con 'text / html' en lugar de 'text / plain'. Actualmente funciona en Chrome y Firefox 22+.
Si este método no es compatible (todos los demás navegadores), entonces
- Guarde el contenido del elemento en un
DocumentFragment
- Vaciar el elemento
- Llamar a la
waitForPastedData
función
La waitforpastedata
función:
Esta función primero sondea los datos pegados (una vez cada 20 ms), lo cual es necesario porque no aparece de inmediato. Cuando aparecieron los datos:
- Guarda el innerHTML del div editable (que ahora son los datos pegados) en una variable
- Restaura el contenido guardado en el DocumentFragment
- Llama a la función 'processPaste' con los datos recuperados
La processpaste
función:
Hace cosas arbitrarias con los datos pegados. En este caso, solo alertamos los datos, puede hacer lo que quiera. Probablemente desee ejecutar los datos pegados a través de algún tipo de proceso de desinfección de datos.
Guardar y restaurar la posición del cursor
En una situación real, es probable que desee guardar la selección antes y restaurarla después ( establezca la posición del cursor en contentEditable <div> ). Luego, podría insertar los datos pegados en la posición en la que se encontraba el cursor cuando el usuario inició la acción de pegar.
Recursos:
Gracias a Tim Down por sugerir el uso de un DocumentFragment, y sobretodo por detectar un error en Firefox debido al uso de DOMStringList en lugar de una cadena para clipboardData.types