一尘不染

从contentEditable div提取文本

css

我将div设置为,contentEditable并设置了“ white-space:pre
样式,以便保留换行符。在Safari,FF和IE中,div的外观和工作原理几乎相同。一切都很好。我想做的是从该div中提取文本,但要确保其格式不会丢失-
特别是换行符。

我们使用的是jQuery,它的text()功能基本上是执行预定的DFS,并将DOM分支中的所有内容粘合在一起。这会丢失格式。

我看过该html()函数,但似乎所有这三种浏览器都使用contentEditablediv
幕后生成的实际HTML来执行不同的操作。假设我在div中输入以下内容:

1
2
3

结果如下:

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>

啊。这里没有什么非常一致的。令人惊讶的是,MSIE看起来最理智!(大写的P标签和全部)

div将使用CSS完成动态设置的样式(字体,颜色,大小和对齐方式),因此我不确定是否可以使用pre标签(在使用Google找到的某些页面上已经提到过)。

有谁知道任何JavaScript代码和/或jQuery插件,或会从contentEditable div中提取文本以保留换行符的方式吗?
如果不需要的话,我不想重塑解析轮。

更新:我getText从jQuery 1.4.2 抄写了该函数,并对其进行了修改,以便使用几乎完整的空格将其提取(我只在添加换行符的地方换了一行);

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;
}

我调用此函数,并使用其输出使用jQuery将其分配给XML节点,例如:

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

最终将生成的XML通过AJAX调用发送到服务器。

这在Safari和Firefox中效果很好。

在IE上,似乎只保留了第一个’\ n’。进一步研究,看起来jQuery正在像这样设置文本(jQuery-1.4.2.js的第4004行):

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

阅读createTextNode,看来IE的实现可能会混用空白。这是真的还是我做错了什么?


阅读 753

收藏
2020-05-16

共1个答案

一尘不染

直到现在,当Nico对其悬赏时,我都忘记了这个问题。

我通过编写自己需要的功能,从现有的jQuery代码库中编写一个功能并对其进行修改以根据需要工作来解决了该问题。

我已经使用Safari(WebKit),IE,Firefox和Opera对该功能进行了测试。因为整个contentEditable都是非标准的,所以我没有费心检查其他任何浏览器。如果任何浏览器的更新更改了实现contentEditable的方式,也可能会破坏该功能。所以程序员要当心。

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;
}
2020-05-16