46 votes

Extraction de texte à partir d'un contenu contentEditable

J'ai un div ensemble d' contentEditable et de style avec "white-space:pre" de sorte qu'il garde les choses comme mais les sauts de ligne. Dans Safari, FF et IE, la div assez bien ressemble et fonctionne de la même façon. Tout est bien. Ce que je veux faire est d'extraire le texte de cette div, mais de telle manière à ne pas perdre la mise en forme-plus précisément, les sauts de ligne.

Nous sommes à l'aide de jQuery, dont l' text() fonction fait une pré-commande DFS et les colles ensemble le contenu de cette branche de la DOM en un seul morceau. Ce perd la mise en forme.

J'ai eu un coup d'oeil à l' html() de la fonction, mais il semble que tous les trois navigateurs à faire des choses différentes avec le HTML qui est généré derrière les scènes dans ma contentEditable div. En supposant que je tape ceci dans mon div:

1
2
3

Ce sont les résultats:

Safari 4:

1
<div>2</div>
<div>3</div>

Firefox 3.6:

1
<br _moz_dirty="">
2
<br _moz_dirty="">
3
<br _moz_dirty="">
<br _moz_dirty="" type="_moz">

IE 8:

<P>1</P><P>2</P><P>3</P>

Ugh. Rien de très cohérent ici. La chose surprenante est que MSIE semble le plus sain d'esprit! (En majuscule balise P et tout et tout)

La div devra définir dynamiquement le style (police de caractères, la couleur, la taille et l'alignement) qui est fait à l'aide de CSS, donc je ne sais pas si je peux utiliser un pre balise (qui a été évoqué sur certaines pages, j'ai trouvé à l'aide de Google).

Personne ne sait de tout code JavaScript et/ou jQuery plugin ou quelque chose qui va extraire du texte à partir d'un contentEditable div de façon à préserver mais les sauts de ligne? Je préfère ne pas réinventer une analyse de la roue si je n'ai pas d'.

Mise à jour: j'ai chipé l' getText fonction de jQuery 1.4.2 et modifié afin de l'extraire avec un espace en grande partie intact (je ne chnaged une ligne où je ajouter un saut de ligne);

function extractTextWithWhitespace( elems ) {
    var ret = "", elem;

    for ( var i = 0; elems[i]; i++ ) {
        elem = elems[i];

        // Get the text from text nodes and CDATA nodes
        if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
            ret += elem.nodeValue + "\n";

        // Traverse everything else, except comment nodes
        } else if ( elem.nodeType !== 8 ) {
            ret += extractTextWithWhitespace2( elem.childNodes );
        }
    }

    return ret;
}

J'appelle cette fonction et l'utiliser à sa sortie de l'attribuer à un nœud XML avec jQuery, quelque chose comme:

var extractedText = extractTextWithWhitespace($(this));
var $someXmlNode = $('<someXmlNode/>');
$someXmlNode.text(extractedText);

Le XML résultant est ensuite envoyé à un serveur via un appel AJAX.

Cela fonctionne bien dans Safari et Firefox.

Sur IE, seul le premier '\n' semble avoir conservé quelque sorte. La recherche en elle plus, il ressemble à jQuery est de définir le texte comme (ligne 4004 de jQuery-1.4.2.js):

return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );

À lire sur createTextNode, il semble que IE mise en œuvre peut mash up de l'espace. Est-ce vrai ou suis-je en train de faire quelque chose de mal?

36voto

Nick Craver Points 313913

Malheureusement, vous n'avez encore à gérer cela pour l' pre cas individuellement par navigateur (je ne cautionne pas du navigateur de détection dans de nombreux cas, l'utilisation de la fonctionnalité de détection...mais dans ce cas, il est nécessaire), mais heureusement, vous pouvez prendre soin d'eux tous assez concise, comme ceci:

var ce = $("<pre />").html($("#edit").html());
if($.browser.webkit) 
  ce.find("div").replaceWith(function() { return "\n" + this.innerHTML; });    
if($.browser.msie) 
  ce.find("p").replaceWith(function() { return this.innerHTML  +  "<br>"; });
if($.browser.mozilla || $.browser.opera ||$.browser.msie )
  ce.find("br").replaceWith("\n");

var textWithWhiteSpaceIntact = ce.text();

Vous pouvez le tester ici. C'est à dire en particulier, est un tracas en raison de la façon dont est n' &nbsp; et de nouvelles lignes dans le texte de la conversion, c'est pourquoi il obtient l' <br> traitement ci-dessus pour le rendre compatible, donc il a besoin de 2 laissez-passer pour être traités correctement.

Dans ce qui précède #edit est l'ID de l' contentEditable composant, il suffit donc de changer cela, ou d'en faire une fonction, par exemple:

function getContentEditableText(id) {
    var ce = $("<pre />").html($("#" + id).html());
    if ($.browser.webkit)
      ce.find("div").replaceWith(function() { return "\n" + this.innerHTML; });
    if ($.browser.msie)
      ce.find("p").replaceWith(function() { return this.innerHTML + "<br>"; });
    if ($.browser.mozilla || $.browser.opera || $.browser.msie)
      ce.find("br").replaceWith("\n");

    return ce.text();
}

Vous pouvez tester que ici. Ou, puisque c'est construit sur les méthodes jQuery de toute façon, faire un plugin, comme ceci:

$.fn.getPreText = function () {
    var ce = $("<pre />").html(this.html());
    if ($.browser.webkit)
      ce.find("div").replaceWith(function() { return "\n" + this.innerHTML; });
    if ($.browser.msie)
      ce.find("p").replaceWith(function() { return this.innerHTML + "<br>"; });
    if ($.browser.mozilla || $.browser.opera || $.browser.msie)
      ce.find("br").replaceWith("\n");

    return ce.text();
};

Ensuite, vous pouvez simplement appeler avec des $("#edit").getPreText(), vous pouvez tester cette version ici.

4voto

Shaggy Frog Points 20388

J'ai oublié à propos de cette question jusqu'à maintenant, lorsque Nico giflé une prime sur elle.

J'ai résolu le problème en écrivant la fonction que j'ai besoin moi-même, mur de soutènement d'une fonction à partir de l'existant jQuery base de code et de le modifier pour fonctionner comme j'ai besoin.

J'ai testé cette fonction avec Safari (WebKit), IE, Firefox et Opera. Je n'ai pas pris la peine de vérifier tout les autres navigateurs depuis l'ensemble de la contentEditable chose est non-standard. Il est également possible qu'une mise à jour de n'importe quel navigateur pourrait casser cette fonction si ils changent la façon dont ils mettent en œuvre contentEditable. Donc, programmeur, méfiez-vous.

function extractTextWithWhitespace(elems)
{
    var lineBreakNodeName = "BR"; // Use <br> as a default
    if ($.browser.webkit)
    {
        lineBreakNodeName = "DIV";
    }
    else if ($.browser.msie)
    {
        lineBreakNodeName = "P";
    }
    else if ($.browser.mozilla)
    {
        lineBreakNodeName = "BR";
    }
    else if ($.browser.opera)
    {
        lineBreakNodeName = "P";
    }
    var extractedText = extractTextWithWhitespaceWorker(elems, lineBreakNodeName);

    return extractedText;
}

// Cribbed from jQuery 1.4.2 (getText) and modified to retain whitespace
function extractTextWithWhitespaceWorker(elems, lineBreakNodeName)
{
    var ret = "";
    var elem;

    for (var i = 0; elems[i]; i++)
    {
        elem = elems[i];

        if (elem.nodeType === 3     // text node
            || elem.nodeType === 4) // CDATA node
        {
            ret += elem.nodeValue;
        }

        if (elem.nodeName === lineBreakNodeName)
        {
            ret += "\n";
        }

        if (elem.nodeType !== 8) // comment node
        {
            ret += extractTextWithWhitespace(elem.childNodes, lineBreakNodeName);
        }
    }

    return ret;
}

1voto

user10 Points 2272

voir ce violon

Ou ce post

Comment analyser le texte éditable de DIV avec la compatibilité du navigateur

créé après beaucoup d'effort ...........

1voto

alfadog67 Points 149

J'ai découvert ça aujourd'hui dans Firefox:

Je passe un contenteditable div qui est des blancs est réglée sur "pre" pour cette fonction, et il fonctionne fortement.

J'ai ajouté une ligne pour indiquer le nombre de nœuds il y a, et un bouton qui permet de mettre la sortie dans un autre PRÉ, juste pour prouver que la mais les sauts de ligne sont intacts.

Il dit en gros ceci:

For each child node of the DIV,
   if it contains the 'data' property,
      add the data value to the output
   otherwise
      add an LF (or a CRLF for Windows)
}
and return the result.

Il y a un problème, tho. Lorsque vous appuyez sur entrée à la fin de chaque ligne du texte original, au lieu de mettre un LF, il met un "Â" dans. Vous pouvez appuyez sur "entrée" et il met une LF, mais pas la première fois. Et vous devez supprimer le "Â" (il ressemble à un espace). Allez comprendre, je pense que c'est un bug.

Cela ne se produit pas avec IE8. (changement textContent à innerText) Il y a un autre bug il y a, tho. Lorsque vous appuyez sur entrée, il divise le nœud 2 nœuds, comme il le fait dans Firefox, mais les "données" de la propriété de chacun de ces nœuds devient alors "undefined".

Je suis sûr qu'il ya beaucoup plus de choses ici que rencontre l'oeil, de sorte que toute entrée sur le sujet sera éclairante.

<!DOCTYPE html>
<html>
<HEAD>
<SCRIPT type="text/javascript">
    function htmlToText(elem) {
        var outText="";
        for(var x=0; x<elem.childNodes.length; x++){
            if(elem.childNodes[x].data){
                outText+=elem.childNodes[x].data;
            }else{
                outText+="\n";
            }
        }
        alert(elem.childNodes.length + " Nodes: \r\n\r\n" + outText);
        return(outText);
    }
</SCRIPT>
</HEAD>
<body>

<div style="white-space:pre;" contenteditable=true id=test>Text in a pre element
is displayed in a fixed-width
font, and it preserves
both      spaces and
line breaks
</DIV>
<INPUT type=button value="submit" onclick="document.getElementById('test2').textContent=htmlToText(document.getElementById('test'))">
<PRE id=test2>
</PRE>
</body>
</html>

0voto

Martin Points 4219

Aucune chance d'utiliser une zone de texte à la place? Il apporte toutes les fonctionnalités dont vous avez besoin.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X