How to get the HTML before, inside, and after a se

2019-04-21 12:02发布

问题:

Here is what I am trying to accomplish: When a user uses a mouse, keyboard, or touch to select text inside "myDiv" I want to acquire three discreet chunks of HTML: the HTML before the selection (to the "left" of it), the HTML inside the selection, and the HTML after the selection (to the "right" of it). The html should be as it would appear with myDiv.innerHTML.

The selection might start or end inside a tag pair (i.e., the isolated selection isn't necessarily valid HTML). I don't need to deal with special scenarios like absolute-positioned elements within the selection; all of the selections I am concerned with will be constrained to one div that will contain basic tags like strong, em, ul, ol, h1, image, and table.

The closest I've come is using rangy to snag the selection and calling selection.getRangeAt(0).cloneContents() to get the selection HTML. This works well enough until I make a selection that is invalid in isolation, and the browser alters the HTML of the document fragment to make it valid markup.

Extra Information: Here's why I need this:

I am creating a document feedback system, so I need to save the selection information to a database for later retrieval and reconstitution. Normally I would save the selection using the DOM path and the selected text, but the text may change between saving and reconstitution. For example, the author might move entire paragraphs around, delete sections, etc. The DOM path becomes pretty useless then.

So my (imperfect) plan is to store the selection as [offset, length, html_snippet]. That's the "position". I'll also store the html snippets that came directly before and after the selected text. This is the "context".

Using a combination of these data I should be able to relocate the originally selected text most of the time, even if it has moved or partially changed. When that fails, the UI will have a way to address it, but I'd like that to occur as infrequently as possible.

Superthanks!

回答1:

I have several questions:

1.- When you say 'the html after the selection' - how would that html be any different than the html previous to the selection or viceversa? Is the 'selection' process itself tampering with the html because of your 'script' or whatever?

2.- You said the text selections are not taking place in textareas...what elements are you working with then? paragraphs? divs...? Narrowing it down would help.

3.- Have you thought about using jquery?

http://api.jquery.com/select/

Doing something like

$('#element_with_text_goes_here').select(function() {

//apply grabbing functions here, for example

//copy html 'before' selection:
     $pre_html = $('html').clone();

   // copy selection...see below:

   // copy html 'after' selection'...same as before


});

Copy selection:

As noted here:

Selecting text in an element (akin to highlighting with your mouse)

Jason wrote the following function:

function selectText(element) {
    var doc = document;
    var text = doc.getElementById(element);    

    if (doc.body.createTextRange) { // ms
        var range = doc.body.createTextRange();
        range.moveToElementText(text);
        range.select();
    } else if (window.getSelection) { // moz, opera, webkit
        var selection = window.getSelection();            
        var range = doc.createRange();
        range.selectNodeContents(text);
        selection.removeAllRanges();
        selection.addRange(range);
    }
}

With a live working demo that can be found here: http://jsfiddle.net/edelman/KcX6A/339/

And a jquery plugin version here: http://jsfiddle.net/edelman/KcX6A/340/

Which you can use for the obtention of the selected text. You'll just have to tweak it accordingly since he was approaching it from a reversed angle. The more details you can give us...the better we can help.

Hope this helps
G



回答2:

This code gets html/text from user's selection, but it works in IE only. The code works with cross-tag selection too. (Globals used to keep the code short.)

<script>
function selected(){
    thediv=document.getElementById('div');
    res=document.getElementById('htm');
    userSelection=document.selection;
    userRange=userSelection.createRange();
    /* For wider scale of elements */
    // rangeParent=userRange.parentElement();
    // if(rangeParent!=thediv) userRange.moveToElementText(rangeParent);
    rangeText=userRange.htmlText;   // OR: rangeText=userRange.text;
    res.innerText=rangeText;    
    return; 
}    
</script>
</head>    
<body onload="document.onselectionchange=selected;">
<div id="div">
<h1>The great testpage</h1>
<p>A paragraph with some text</p>
<p>This paragraph <b>contains</b> a child element.</p>
<p>And this is the last paragraph.</p>
<table>
<tr><td>Cell1-1</td><td>cell1-2</td></tr>
<tr><td>Cell2-1</td><td>cell2-2</td></tr>
</table>
<ol>
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ol>
</div>
<br>
<span id="htm"></span>
</body>

Content before&after selection in the thediv you'll get like this: prepost=thediv.innerHTML/innerText.split(rangeText);

If the page contains any other elements but thediv, they have to be made unselectable.