简体   繁体   中英

How do I select arbitrary text on the page using javascript?

Let's say I have a contentEditable div , to the user can edit and change the text and elements inside it. How do I arbitrarily change the selection in this div with javascript? By "change" I don't mean "change the contents of whatever the user has selected", I mean actually change what is selected. The user should then be able to type over the selection, replacing it with something else.

This should take into account that I may want to select text across elements. For instance:

<p>Some text <span>goes</span> here.</p>

I may for instance want to select "Some text go", or everything inside the <p> .

This only needs to work in Safari/Webkit.

Thanks in advance. As a native code developer, I find the DOM and Javascript in general quite frustrating.

Just to answer my own question in detail so anyone searching for something similar doesn't have to go looking elsewhere...

The code I ended up using was something like this:

var range = document.createRange();
range.setStart( <get the node the selection starts in>, <char offset in that node> );
range.setEnd( <get the node the selection ends in>, <char offset in that node> ); 

window.getSelection().removeAllRanges();
window.getSelection().addRange(range);

Big thanks to James Black for pointing me in the right direction.

You can use document.getElementById('your_text_id').setSelectionRange(start, end); and you can use Math.random() to generate random numbers for start and end

Unless you need to write your own, you may want to look at tinyMCE, http://tinymce.moxiecode.com/ , as it is a nice WYSIWYG editor in javascript.

In order to do this you will probably want to look at something like this: http://codingtricks.blogspot.com/2009/03/javascript-select-partial-text-in-div.html

These may also be helpful: JavaScript ranging gone wrong https://developer.mozilla.org/en/DOM/window.getSelection

What you are trying to do will be complex, as you will need to take the selected area, remove all the tags, then put in the tag that you want for the selected area.

While @Lucas's answer is good, there is a lot missing that would allow you to successfully use this. The node the selection starts in has to be the exact node, not a parent. In our case we were trying to put some text into a TextAngular control, then select text that looked liked ____ so the user could "fill in the blank".

Our input was html of the order <p>Some text goes here: _____</p> or

<p>Some partial goes here
<ul>
    <li>Option 1</li>
    <li>_____</li>
</ul>

To get this to work, we had to write something to find the underscores in the right element

function find_(node) {
    var i, n;
    // return the node with the _'s
    for(i=0; i < node.childNodes.length; ++i) {
        n = node.childNodes[i];
        console.debug(n);
        if(n.textContent) {
            console.debug(n, n.textContent);
            if(n.textContent.search(/___+/) > 0) {
                return n;
            }
        }
        if(n.childNodes) {
            console.debug(n, n.childNodes);
            n = find_(n);
            if(n) {
                return n;
            }
        }
    }
    return null;
}

So in the end, finding the node to satisfy <get the node the selection starts in> was a lot more work than that simple sentence led me to believe.

In the <ul> case. the node that contains the ____ is firstChild of the li node.

I've put this here to help others that need to do this not wonder why they are getting the error message

IndexSizeError: Failed to execute 'setStart' on 'Range': There is no child at offset 65.

When the problem is they are just looking at the wrong node.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM