1

I have a textarea containing HTML, and a div rendering this HTML.
What I'd like to do is getting the selection positions (start and end) in the innerHTML whenever I select text either in the textarea or in the div.

I already managed to get the positions when I select text in the textarea (as there are easy ways to do it for either textarea or input), but I struggle with the div part.

This answer helped me getting the selected HTML, but there are two problems with this:

  • If the same piece of HTML is present twice, using string.indexOf to get the position will always get me the position of the first occurrence
  • Whenever I select a part of an element (may it be <li>, <u>, <b>, <i>, etc), the function adds the corresponding tag, so the selected HTML does not match the innerHTML.
    • Say if I select tu</b></li><li><i>Pi in the example below, I will get <li><b>tu</b></li><li><i>Pi</i></li> instead.

updateDiv();

function updateDiv() {
  $("#myDiv").html($("#myArea").val());
}

function myTest() {
  var html = "";    

  if (typeof window.getSelection != "undefined") {
        var sel = window.getSelection();
        
        if (sel.rangeCount) {
            var container = document.createElement("div");
            for (var i = 0, len = sel.rangeCount; i < len; ++i) {
                container.appendChild(sel.getRangeAt(i).cloneContents());
            }
            html = container.innerHTML;
        }
    } else if (typeof document.selection != "undefined") {
        if (document.selection.type == "Text") {
            html = document.selection.createRange().htmlText;
        }
    }

  if(html.length > 0)
    alert(html);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

<textarea id='myArea' onchange='updateDiv();' rows='12', cols='40'>
  <ol>
    <li>Patata</li>
    <li>
      Petete
      <ul>
        <li><b>Pututu</b></li>
        <li><i>Pititi</i></li>
        <li>Pututu</li>
      </ul>
    </li>
  </ol>
</textarea>

<div id='myDiv' onclick='myTest()'>
</div>

I'd like to be able to perform actions on the content of my textarea based on the selected HTML (hence why I need to get the selection position relative to the div innerHTML).

Rafalon
  • 4,450
  • 2
  • 16
  • 30
  • 1
    Maybe giving the div the `contentEditable` attribute could help (https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Editable_content) -- but your user could change the text and you'd have to change it back. There's no way to know which occurrence of a substring is selected unless you have access to the base string (ie the whole string), but maybe there's a way to get position of the cursor within an editable div? Or, you could use a second `textarea` instead of a div, maybe with the `disabled` or `readonly` attribute (if these don't break your use case) , or just adding div-like styling. – Cat Jul 19 '19 at 11:04
  • Woah! In fact using `contentEditable` might even be better than what I planned to do! Let me just try to see if I can get the position with this :) – Rafalon Jul 19 '19 at 11:07
  • Ok so I didn't manage to get the position with the `div` (so the question still holds), but I can toggle bold, italic, underline on the selected text, so it's quite good already, thanks! :) – Rafalon Jul 22 '19 at 06:22
  • @Rafalon the user only should seleted the HTML render or div content as well? –  Nov 16 '19 at 00:57
  • @x-rw The purpose was for the user to be able to edit the HTML content in either a user-friendly way (select text and tick bold/italic/underline or add bullet lists for example) or a more advanced way (add tags as needed). Therefore, in the end, both rendered and raw HTML should be editable. tl;dr: the user should be able to select both HTML render and div content – Rafalon Nov 18 '19 at 07:33

0 Answers0