Nettoyer le texte collé Microsoft Word en utilisant JavaScript
J'utilise un 'contenteditable' <div/>
et j'active PASTE.
C'est incroyable la quantité de code de balisage qui est collée à partir d'une copie du presse-papiers de Microsoft Word. Je suis en train de lutter contre cela, et j'ai obtenu environ 1/2 chemin en utilisant la fonction stripTags()
des Prototypes (qui ne semble malheureusement pas me permettre de garder quelques balises).
Cependant, même après cela, je me retrouve avec une quantité hallucinante de code de balisage inutile.
Donc ma question Est, y a-t-il une fonction (en utilisant JavaScript), ou approche que je peux utiliser qui va nettoyer la majorité de ce balisage inutile?
9 réponses
Voici la fonction que j'ai fini par écrire qui fait assez bien le travail (pour autant que je sache de toute façon).
Je suis certainement ouvert aux suggestions d'amélioration si quelqu'un en a. Grâce.
function cleanWordPaste( in_word_text ) {
var tmp = document.createElement("DIV");
tmp.innerHTML = in_word_text;
var newString = tmp.textContent||tmp.innerText;
// this next piece converts line breaks into break tags
// and removes the seemingly endless crap code
newString = newString.replace(/\n\n/g, "<br />").replace(/.*<!--.*-->/g,"");
// this next piece removes any break tags (up to 10) at beginning
for ( i=0; i<10; i++ ) {
if ( newString.substr(0,6)=="<br />" ) {
newString = newString.replace("<br />", "");
}
}
return newString;
}
J'espère que cela est utile à certains d'entre vous.
Vous pouvez soit utiliser le CKEditor complet qui nettoie sur la pâte, soit regarder la source.
J'utilise ceci:
$(body_doc).find('body').bind('paste',function(e){
var rte = $(this);
_activeRTEData = $(rte).html();
beginLen = $.trim($(rte).html()).length;
setTimeout(function(){
var text = $(rte).html();
var newLen = $.trim(text).length;
//identify the first char that changed to determine caret location
caret = 0;
for(i=0;i < newLen; i++){
if(_activeRTEData[i] != text[i]){
caret = i-1;
break;
}
}
var origText = text.slice(0,caret);
var newText = text.slice(caret, newLen - beginLen + caret + 4);
var tailText = text.slice(newLen - beginLen + caret + 4, newLen);
var newText = newText.replace(/(.*(?:endif-->))|([ ]?<[^>]*>[ ]?)|( )|([^}]*})/g,'');
newText = newText.replace(/[·]/g,'');
$(rte).html(origText + newText + tailText);
$(rte).contents().last().focus();
},100);
});
Body_doc est l'iframe modifiable, si vous utilisez un div modifiable, vous pouvez supprimer le .trouver ('corps') partie. Fondamentalement, il détecte un événement de collage, vérifie l'emplacement nettoie le nouveau texte, puis place le texte nettoyé là où il a été collé. (Cela semble déroutant... mais ce n'est pas vraiment aussi mauvais que cela puisse paraître.
Le setTimeout est nécessaire car vous ne pouvez pas saisir le texte tant qu'il n'est pas réellement collé dans l'élément, les événements de collage se déclenchent dès que le pâte commence.
Que diriez-vous d'avoir un bouton "Coller en texte brut" qui affiche un <textarea>
, permettant à l'utilisateur de coller le texte là-dedans? de cette façon, toutes les étiquettes seront supprimées pour vous. C'est ce que je fais avec mon CMS; j'ai renoncé à essayer de nettoyer le désordre de Word.
J'ai fait quelque chose comme ça il y a longtemps, où j'ai totalement nettoyé les choses dans un éditeur de texte enrichi et converti les balises de police en styles, brs en p, etc., pour le garder cohérent entre les navigateurs et empêcher certaines choses laides d'entrer via paste. J'ai pris ma fonction récursive et en ai arraché la majeure partie sauf pour la logique de base, cela pourrait être un bon point de départ ("result" est un objet qui accumule le résultat, qui prend probablement une deuxième passe pour convertir en une chaîne), si c'est quoi vous avez besoin de:
var cleanDom = function(result, n) {
var nn = n.nodeName;
if(nn=="#text") {
var text = n.nodeValue;
}
else {
if(nn=="A" && n.href)
...;
else if(nn=="IMG" & n.src) {
....
}
else if(nn=="DIV") {
if(n.className=="indent")
...
}
else if(nn=="FONT") {
}
else if(nn=="BR") {
}
if(!UNSUPPORTED_ELEMENTS[nn]) {
if(n.childNodes.length > 0)
for(var i=0; i<n.childNodes.length; i++)
cleanDom(result, n.childNodes[i]);
}
}
}
Cela fonctionne très bien pour supprimer tous les commentaires du texte HTML, y compris ceux de Word:
function CleanWordPastedHTML(sTextHTML) {
var sStartComment = "<!--", sEndComment = "-->";
while (true) {
var iStart = sTextHTML.indexOf(sStartComment);
if (iStart == -1) break;
var iEnd = sTextHTML.indexOf(sEndComment, iStart);
if (iEnd == -1) break;
sTextHTML = sTextHTML.substring(0, iStart) + sTextHTML.substring(iEnd + sEndComment.length);
}
return sTextHTML;
}
Avait un problème similaire avec les sauts de ligne comptés comme des caractères et j'ai dû les supprimer.
$(document).ready(function(){
$(".section-overview textarea").bind({
paste : function(){
setTimeout(function(){
//textarea
var text = $(".section-overview textarea").val();
// look for any "\n" occurences and replace them
var newString = text.replace(/\n/g, '');
// print new string
$(".section-overview textarea").val(newString);
},100);
}
});
});
Pourriez-vous coller dans une zone de texte cachée, copier à partir de la même zone de texte et coller sur votre cible?
Je déteste le dire, mais j'ai finalement renoncé à faire de la merde de mot TinyMCE comme je le veux. Maintenant, je viens d'avoir un email envoyé à moi chaque fois que l'entrée d'un utilisateur contient certains HTML (recherchez <span lang="en-US">
par exemple) et je le corrige manuellement.