Solution n ° 1 (texte brut uniquement et nécessite Firefox 22+)
Fonctionne pour IE6 +, FF 22+, Chrome, Safari, Edge (testé uniquement dans IE9 +, mais devrait fonctionner pour les versions inférieures)
Si vous avez besoin de support pour coller du HTML ou Firefox <= 22, consultez la solution 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/
Notez que cette solution utilise le paramètre 'Text' pour la getDatafonction, qui n'est pas standard. Cependant, cela fonctionne dans tous les navigateurs au moment de la rédaction.
Solution # 2 (HTML et fonctionne pour Firefox <= 22)
Testé dans 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/
Explication
L' onpasteévénement du diva la handlePastefonction qui lui est attachée et a passé un seul argument: l' eventobjet de l'événement coller. Un intérêt particulier pour nous est la clipboardDatapropriété de cet événement qui permet d'accéder au presse-papiers dans des navigateurs non-ie. Dans IE, l'équivalent est window.clipboardData, bien que celui-ci ait une API légèrement différente.
Voir la section des ressources ci-dessous.
La handlepastefonction:
Cette fonction a deux branches.
Le premier vérifie l'existence event.clipboardDataet vérifie si sa typespropriété contient 'text / html' ( typespeut être soit un DOMStringListqui est vérifié en utilisant la containsméthode, soit une chaîne qui est vérifiée en utilisant la indexOfméthode). Si toutes ces conditions sont remplies, nous procédons comme dans la solution n ° 1, sauf avec 'text / html' au lieu de 'text / plain'. Cela fonctionne actuellement dans Chrome et Firefox 22+.
Si cette méthode n'est pas prise en charge (tous les autres navigateurs), nous
- Enregistrez le contenu de l'élément dans un
DocumentFragment
- Vider l'élément
- Appelez la
waitForPastedDatafonction
La waitforpastedatafonction:
Cette fonction interroge d'abord les données collées (une fois toutes les 20 ms), ce qui est nécessaire car elles n'apparaissent pas immédiatement. Lorsque les données sont apparues, elles:
- Enregistre le innerHTML du div modifiable (qui est maintenant les données collées) dans une variable
- Restaure le contenu enregistré dans DocumentFragment
- Appelle la fonction 'processPaste' avec les données récupérées
La processpastefonction:
Fait des choses arbitraires avec les données collées. Dans ce cas, nous alertons simplement les données, vous pouvez faire ce que vous voulez. Vous souhaiterez probablement exécuter les données collées via une sorte de processus de nettoyage des données.
Sauvegarde et restauration de la position du curseur
Dans une situation réelle, vous voudrez probablement enregistrer la sélection avant et la restaurer après ( définir la position du curseur sur contentEditable <div> ). Vous pouvez ensuite insérer les données collées à la position où se trouvait le curseur lorsque l'utilisateur a lancé l'action de collage.
Ressources:
Merci à Tim Down d'avoir suggéré l'utilisation d'un DocumentFragment et abligh pour avoir détecté une erreur dans Firefox due à l'utilisation de DOMStringList au lieu d'une chaîne pour clipboardData.types