Solução nº 1 (somente texto sem formatação e requer o Firefox 22+)
Funciona para IE6 +, FF 22+, Chrome, Safari, Edge (testado apenas no IE9 +, mas deve funcionar para versões inferiores)
Se você precisar de suporte para colar HTML ou Firefox <= 22, consulte a Solução 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/
Observe que esta solução usa o parâmetro 'Texto' para a getData
função, que não é padrão. No entanto, ele funciona em todos os navegadores no momento da escrita.
Solução 2 (HTML e funciona no Firefox <= 22)
Testado no 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/
Explicação
O onpaste
evento do div
possui a handlePaste
função anexada e transmitiu um único argumento: o event
objeto para o evento de colagem. De particular interesse para nós, é a clipboardData
propriedade deste evento que permite o acesso à área de transferência em navegadores que não sejam. No IE, o equivalente é window.clipboardData
, embora isso tenha uma API ligeiramente diferente.
Veja a seção de recursos abaixo.
A handlepaste
função:
Esta função tem dois ramos.
A primeira verifica a existência de event.clipboardData
e verifica se sua types
propriedade contém 'text / html' ( types
pode ser um DOMStringList
que é verificado usando o contains
método ou uma string que é verificada usando o indexOf
método). Se todas essas condições forem atendidas, procederemos como na solução 1, exceto com 'text / html' em vez de 'text / plain'. Atualmente, ele funciona no Chrome e Firefox 22+.
Se esse método não for suportado (todos os outros navegadores), então nós
- Salve o conteúdo do elemento em um
DocumentFragment
- Esvaziar o elemento
- Chame a
waitForPastedData
função
A waitforpastedata
função:
Essa função pesquisa primeiro os dados colados (uma vez a cada 20ms), o que é necessário porque não aparece imediatamente. Quando os dados aparecerem:
- Salva o innerHTML da div editável (que agora são os dados colados) em uma variável
- Restaura o conteúdo salvo no DocumentFragment
- Chama a função 'processPaste' com os dados recuperados
A processpaste
função:
Faz coisas arbitrárias com os dados colados. Nesse caso, apenas alertamos os dados, você pode fazer o que quiser. Você provavelmente desejará executar os dados colados através de algum tipo de processo de limpeza de dados.
Salvando e restaurando a posição do cursor
Em uma situação real, você provavelmente desejaria salvar a seleção antes e restaurá-la depois ( Defina a posição do cursor em contentEditable <div> ). Você pode inserir os dados colados na posição em que o cursor estava quando o usuário iniciou a ação de colar.
Recursos:
Agradecemos a Tim Down por sugerir o uso de um DocumentFragment, e também por detectar um erro no Firefox devido ao uso de DOMStringList em vez de uma string para clipboardData.types