javascripthtmltextselection

Get selection offsets in JS/HTML with formatting information


I am building a web interface for annotating texts. The user should select a portion of the text (using the mouse) and write some side notes about it. When I save the annotation, I need to keep the offsets of the selected text. Note that the text is taken from a TXT file that may include spaces, tabulations, newlines, etc.

Now I put the text into a <pre> tag and call the Selection object in JS to get the offsets. By using a <pre> container, I have perfect correspondence between the offsets of the selection and the offsets in the TXT file.

Now I need to add some formatting information on this text (for instance, highlight the portions of text already annotated by other users): if I add some <span>s with the background color, I mess the information about the selection and the offsets.

Any idea on how to deal with this problem?

$(document).ready(function() {
    $("#button").click(function() {
    const selection = window.getSelection()

    let selectedText = selection.toString()
    let startOffset = selection.anchorOffset
    let endOffset = selection.focusOffset
    
    console.log(selectedText, startOffset, endOffset)
  })
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<pre id="file-content">This is my text.

I can have spaces     and newlines.


Bye!</pre>

<button id="button">
Click me
</button>


Solution

  • This is an interesting problem, since the methods offered by window.getSelection API return selection offset from the innermost tag, we must find a hacky solution.

    I suggest having 2 pre tags which the text contents are the same inside. first one is used only as a container which user can select the text from. and second will contain all the span tags used for styling and annotation and etc..

     <div style="width:300px; height:300px; position:relative">
                <!-- This pre tag is used only for keeping the text as plain portion of text -->
                <pre id="userSelection" style="position:absolute;margin:0;top:0;color:rgba(0,0,0,0);">
                    lorem ipsum, dolor sit amet consectetur adipisicing elit.Sint praesentium, ad repellat fuga consequuntur aut a laboriosam! Deserunt, fugiat aperiam, omnis esse vel, aliquid itaque in tempore sequi voluptatibus consequuntur.
                </pre>
                <!-- Using this tag you can style the elements-->
                <pre style="margin:0;z-index:0;user-select: none;">
                    lorem ipsum, dolor sit amet consectetur <span style="color:red;">adipisicing</span> elit.Sint praesentium, ad repellat fuga consequuntur aut a laboriosam! Deserunt, fugiat aperiam, omnis esse vel, aliquid itaque in tempore sequi voluptatibus consequuntur.
                </pre>
    
                <button onclick="handleClick()">Click here</button>
            </div>
    

    If you check the provided code above, second tag in this example contains the span for the word adipisicing, your JavaScript example will return adipisicing 56 67 which is the correct result.


    Important note: