关于javascript:在Firefox中替换所选文本

Replace selected text in Firefox

如何在Firefox中使用PURE javascript将所选文本替换为其他文本?

我用来获取选择:

1
2
var sel = this.getSelection();
var range = sel.getRangeAt(0);

还有这个重要的问题:
我想保留字符的原始格式(当然,新字符串将具有正确的格式)
选择可以"跨元素"完成(这意味着选择可以包含一个元素(如div或table)中的某些文本以及其他元素中的某些文本)。

例如,文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 this is a test


still a test

 <table style="width:100%;">
        <tr>
            <td>
                another word</td>
            <td>
                stackoverflow</td>
        </tr>
        <tr>
            <td>
                bump</td>
            <td>
               </td>
        </tr>
    </table>

用户(通过一项选择)选择以下文本:

his is a test still a test anot

所以现在我想替换保留格式的文本,例如用新字符串=替换所有内容

XXX XX X XXXX XXXXX X XXXX XXXX

最终文件(替换后)将为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 tXXX XX X XXXX


XXXXX X XXXX

 <table style="width:100%;">
        <tr>
            <td>
                XXXXher word</td>
            <td>
                stackoverflow</td>
        </tr>
        <tr>
            <td>
                bump</td>
            <td>
               </td>
        </tr>
    </table>

哇,真是可惜!

使用Javascript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
var sel, range, nodevalue, startFound, stop;

function goThroughElements(el){
    // If el is the start node, set startFound to true
    if(el.isSameNode(range.startContainer)) startFound = true;

    if(startFound){
        // If this is the start node, replace the text like this: abcd[ef gh] --> abcdxx xx
        if(el.isSameNode(range.startContainer)){
            // \w stands for a word character
            nodevalue = el.nodeValue.substring(range.startOffset).replace(/\w/g, 'x');
            el.nodeValue = el.nodeValue.substring(0, range.startOffset) + nodevalue;

        }

        // If this is the end node, replace the value like this: [abc def]gh ij -> xxx xxxgh ij
        else if(el.isSameNode(range.endContainer)){
            nodevalue = el.nodeValue.substring(0,range.endOffset).replace(/\w/g, 'x');
            el.nodeValue = nodevalue + el.nodeValue.substring(range.endOffset);

            // Now we can stop
            stop = true;
        }

        // If this is just a text node, replace the value by xxxx
        else if(el.nodeType == 3){
            el.nodeValue = el.nodeValue.replace(/\w/g, 'x')
        }
    }

    // Loop trough el's brothers
    while(el){
        // Stop if we need to
        if(stop) return;

        // If this element has child nodes, call this function again with the first child node
        if(el.hasChildNodes()){
            goThroughElements(el.childNodes[0]);
        }

        // Jump to el's brother, or quit the loop
        if(el.nextSibling)
            el = el.nextSibling;
        else
            break;
    }

}

$(document).ready(function() {
    $(this).mouseup(function(){
        // Get the selection
        sel = window.getSelection();
        range = sel.getRangeAt(0);

        // Stop must be false if the last selected text node isn't found, startFound must be false when the start isn't found
        stop = false; startFound = false;

        if(range.collapsed == false){
            // Check if the selection takes place inside one text node element
            if(range.startContainer.isSameNode(range.endContainer)){
                // ab[cdefg]h  -> aaxxxxxh
                nodevalue = range.startContainer.nodeValue;
                range.startContainer.nodeValue = nodevalue.substring(0, range.startOffset) + nodevalue.substring(range.startOffset, range.endOffset).replace(/\w/g, 'x') + nodevalue.substring(range.endOffset);
            } else {    
                // If the start node of the selection isn't the same as the end node, loop through all elements
                goThroughElements(range.commonAncestorContainer.childNodes[0]);
            }
            // Collapse selection.
            range.collapse(true);
        }            
    });
});

您可以尝试当然的代码

也许这不是最佳解决方案,因为它从根开始搜索起始节点。 从range.startContainerrange.endContainer的第一个公共父元素搜索会更快,但是我不知道该怎么做...

编辑

我将to-X函数包装在if(range.collapsed == false)内,并使用range.commonAncestorContainer.childNodes[0]以便从选区的开始和结束位置的公共父级的第一个子级开始遍历元素