web-dev-qa-db-fra.com

Nettoyer le texte collé Microsoft Word à l'aide de JavaScript

J'utilise un <div/> 'contenteditable' et j'active PASTE.

C'est incroyable la quantité de code de marquage collée à partir d'une copie du Presse-papiers à partir de Microsoft Word. Je me bats contre cela et je suis à peu près de la moitié de la situation en utilisant la fonction stripTags() de Prototypes ( qui ne semble malheureusement pas me permettre de conserver certaines balises ).

Cependant, même après cela, je me retrouve avec une quantité époustouflante de code de balisage inutile.

Ma question est donc la suivante: existe-t-il une fonction (utilisant JavaScript) ou une approche que je peux utiliser pour nettoyer la majeure partie de cette balise inutile?

22
OneNerd

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. Merci.

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 sera utile à certains d'entre vous.

21
OneNerd

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-->))|([ ]?<[^>]*>[ ]?)|(&nbsp;)|([^}]*})/g,'');

                    newText = newText.replace(/[·]/g,'');

                    $(rte).html(origText + newText + tailText);
                    $(rte).contents().last().focus();
                },100);
            });

body_doc est l'iframe éditable. Si vous utilisez un div éditable, vous pouvez supprimer la partie .find ('body'). Fondamentalement, il détecte un événement de collage, vérifie que l'emplacement nettoie le nouveau texte, puis replace le texte nettoyé à l'endroit où il a été collé. (Cela semble déroutant ... mais ce n'est pas aussi grave que ça en a l'air.

SetTimeout est nécessaire car vous ne pouvez pas saisir le texte tant qu'il n'est pas collé dans l'élément. Les événements de collage sont déclenchés dès le début du collage.

3
Daniel Sellers

Vous pouvez utiliser le CKEditor qui nettoie à la pâte, ou regarder la source .

3
Todd Main

Que diriez-vous d'avoir un bouton "coller en texte brut" qui affiche un <textarea>, permettant à l'utilisateur de coller le texte à l'intérieur? Ainsi, toutes les balises seront effacées pour vous. C'est ce que je fais avec mon CMS. J'ai renoncé à essayer de nettoyer le désordre de Word.

2
Josh

Avait un problème similaire avec les sauts de ligne étant comptés comme des caractères et je devais 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);
    }
  });
  
});
0
ericmotil

Cela fonctionne très bien pour supprimer 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;
}
0
user759463

J'ai fait quelque chose comme ça il y a longtemps, où j'ai totalement nettoyé tout ça dans un éditeur de texte riche et converti les balises de police en styles, brs to p's, etc., pour le garder cohérent entre les navigateurs et empêcher certaines choses laides de passer par la pâte. J'ai pris ma fonction récursive et en ai extrait la plupart, à l'exception de la logique de base, ce qui pourrait être un bon point de départ ("result" est un objet qui accumule le résultat, ce qui nécessite probablement une seconde passe pour être converti en chaîne), si c'est ce dont vous avez besoin:

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]);
        }
    }
}
0
rob