Search code examples
javascriptjqueryselection

window.getSelection() offset with HTML tags?


If I have the following HTML:

<div class="content">
Vivamus <span>luctus</span> urna sed urna ultricies ac tempor dui sagittis.
</div>

And I run an event on mouseup that sees the ranges of the selected text:

$(".content").on("mouseup", function () {
    var start = window.getSelection().baseOffset;
    var end = window.getSelection().focusOffset;
    if (start < end) {
        var start = window.getSelection().baseOffset;
        var end = window.getSelection().focusOffset;
    } else {
        var start = window.getSelection().focusOffset;
        var end = window.getSelection().baseOffset;
    }
    console.log(window.getSelection());
    console.log(start + ", " + end);
});

And I select the word Vivamus from the content, it will log 1, 8, as that is the range of the selection.

If, however, I select the word urna, it will log 15, 20, but won't take into account the <span> elements of the HTML.

Is there anyway for focusOffset and baseOffset to also count for HTML tags, instead of just the text?


Solution

  • Update

    Live Example: http://jsfiddle.net/FLwxj/61/

    Using a clearSelection() function and a replace approach, I was able to achieve the desired result.

    var txt = $('#Text').html();
    $('#Text').html(
        txt.replace(/<\/span>(?:\s)*<span class="highlight">/g, '')
    );
    clearSelection();
    

    Sources:


    Below you'll find some working solutions to your problem. I placed them in order of code efficiency.

    Working Solutions

    • https://stackoverflow.com/a/8697302/1085891 (live example)

      window.highlight = function() {
          var selection = window.getSelection().getRangeAt(0);
          var selectedText = selection.extractContents();
          var span = document.createElement("span");
          span.style.backgroundColor = "yellow";
          span.appendChild(selectedText);
          span.onclick = function (ev) {
          this.parentNode.insertBefore(
              document.createTextNode(this.innerHTML), 
              this
          );
          this.parentNode.removeChild(this);
          }
          selection.insertNode(span);
      }
      
    • https://stackoverflow.com/a/1623974/1085891 (live example)

      $(".content").on("mouseup", function () {
         makeEditableAndHighlight('yellow'); 
      });
      
      function makeEditableAndHighlight(colour) {
          sel = window.getSelection();
          if (sel.rangeCount && sel.getRangeAt) {
          range = sel.getRangeAt(0);
          }
          document.designMode = "on";
          if (range) {
          sel.removeAllRanges();
          sel.addRange(range);
          }
          // Use HiliteColor since some browsers apply BackColor to the whole block
          if (!document.execCommand("HiliteColor", false, colour)) {
          document.execCommand("BackColor", false, colour);
          }
          document.designMode = "off";
      }
      
      function highlight(colour) {
          var range, sel;
          if (window.getSelection) {
          // IE9 and non-IE
          try {
              if (!document.execCommand("BackColor", false, colour)) {
              makeEditableAndHighlight(colour);
              }
          } catch (ex) {
              makeEditableAndHighlight(colour)
          }
          } else if (document.selection && document.selection.createRange) {
          // IE <= 8 case
          range = document.selection.createRange();
          range.execCommand("BackColor", false, colour);
          }
      }
      
    • https://stackoverflow.com/a/12823606/1085891 (live example)

    Other helpful solutions: