2

I'm trying to build a selection tool in js, for diverse reasons. To maintain a variety of selections, it's based on the index/ offset in the string. Except that if there is an encoded html character in it, it's considered as one character, and not 4.

Example : https://jsfiddle.net/1nLszqoa/

<div id="banner-message">
  <p>&lt;Hello World</p>
</div>

document.addEventListener('mouseup', function() {
            var selection = document.getSelection();
            
            console.log(selection);
});

If you select "<H", the focusOffset (in console) will be 2. Except that Html wise, it's 5.

Do you know any simple workaround? I know that I could maybe use a textarea instead, but for now I'm pursuing this lead.

Thank you

FTW
  • 922
  • 1
  • 7
  • 19

1 Answers1

1

you can do this hack to calc the offset:

in the jsfiddle that you provided it works faster then stack overflow snippet tool.

document.addEventListener('mouseup', function() {
            var selection = document.getSelection();
            
      //get the text from start to focusOffset
      var text = selection.anchorNode.nodeValue.substring(0, selection.focusOffset);
      //you can do the excape with jquery like this
      //this came from this link: https://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
      //var escaped = $("<div>").text(text).html();
      
      //or only javascript like this 
      var escaped = escapeHtml(text);
      
            console.log(selection);
      console.log(selection.anchorNode.nodeValue.substring(0, selection.focusOffset));
      console.log('focusOffset: ' + selection.focusOffset);
      console.log(escaped);
      console.log('focusOffset hacked: ' + escaped.length);
      
        });
    
    //this came from this link: https://stackoverflow.com/questions/1787322/htmlspecialchars-equivalent-in-javascript
    function escapeHtml(text) {
  var map = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#039;'
  };
  
  return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#banner-message {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  font-size: 25px;
  text-align: center;
  transition: all 0.2s;
  margin: 0 auto;
  width: 300px;
}

button {
  background: #0084ff;
  border: none;
  border-radius: 5px;
  padding: 8px 14px;
  font-size: 15px;
  color: #fff;
}

#banner-message.alt {
  background: #0084ff;
  color: #fff;
  margin-top: 40px;
  width: 200px;
}

#banner-message.alt button {
  background: #fff;
  color: #000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="banner-message">
  <p>&lt;Hello World</p>
</div>
Yair I
  • 1,133
  • 1
  • 6
  • 9
  • You're a genius and as soon as I put my hands on a medal, I'll give it to you. – FTW Jun 05 '21 at 23:02
  • For the encode part, there's a native js version of the jQuery code that you put, that I'm actually using, and it work pretty well: function htmlEncode(str) { var div = document.createElement('div'); var text = document.createTextNode(str); div.appendChild(text); return div.innerHTML; } – FTW Jun 05 '21 at 23:26