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 getData
fonction, 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 div
a la handlePaste
fonction qui lui est attachée et a passé un seul argument: l' event
objet de l'événement coller. Un intérêt particulier pour nous est la clipboardData
proprié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 handlepaste
fonction:
Cette fonction a deux branches.
Le premier vérifie l'existence event.clipboardData
et vérifie si sa types
propriété contient 'text / html' ( types
peut être soit un DOMStringList
qui est vérifié en utilisant la contains
méthode, soit une chaîne qui est vérifiée en utilisant la indexOf
mé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
waitForPastedData
fonction
La waitforpastedata
fonction:
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 processpaste
fonction:
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