Jay Jeong
Jay Jeong

Reputation: 994

How to get a specific selection from contenteditable

What I'm trying to do is to get a selection only for a word I want from contenteditable inputs. For example,

Hello My World

from the above input value, I want to select only the word 'My' and get the string value of it.

so far, I have written a function that gets a selection upto the caret from 0 range like so:

function selectUptoCaret(el){
    var range = window.getSelection().getRangeAt(0);
    var preCaretRange = range.cloneRange();
    preCaretRange.selectNodeContents(el);
    preCaretRange.setEnd(range.endContainer, range.endOffset);

    var sel = window.getSelection()
    sel.removeAllRanges()
    sel.addRange(preCaretRange)
  }

When I click 'y' from the word, 'My', it selects 'Hello My'. but again, I only want to select 'My', not 'Hello My'.

Upvotes: 0

Views: 46

Answers (1)

Ryan Dabler
Ryan Dabler

Reputation: 401

I think you're mostly there, but the problem you're getting of having everything to the left of the caret highlighted probably has to do with the fact you're not calling preCaretRange.setStart() and so it's thinking the start should be zero. I modified your function a little bit in order to get it to select the actual word your cursor is at:

function selectUptoCaret(el){
    var range = window.getSelection().getRangeAt(0);
    var preCaretRange = range.cloneRange();

    var startOffset = range.startContainer.textContent.lastIndexOf(' ', range.startOffset);
    var endOffset = range.endContainer.textContent.indexOf(' ', range.endOffset);

    preCaretRange.selectNodeContents(el);
    preCaretRange.setStart(range.startContainer, ~startOffset ? startOffset + 1: 0);
    preCaretRange.setEnd(range.endContainer, ~endOffset ? endOffset : range.endContainer.textContent.length);

    var sel = window.getSelection()
    sel.removeAllRanges()
    sel.addRange(preCaretRange)
}

My assumption is that the el param passed into selectUptoCaret is the actual contentEditable HTML element.

My changes were:

  • take the cursor position and get the position of the next and previous spaces
  • if there is no previous space (determined by the ~startOffset check) we will start at 0 because we are in the first word
  • if there is no following space (determined by the ~endOffset check) we will use the full length of the text content because we are in the last word.
  • set the setStart on our preCaretRange object to make sure we have a finite start point that is not necessarily the beginning of the text content

Note: my ternary ~startOffset ? startOffset + 1 : 0 is equivalent to saying startOffset > -1 ? startOffset + 1 : 0. Using the ~ bitwise operator is a convenient way of checking that a value is not -1 (since ~ -1 === 0).

This now will only select the current word at your caret's position.

Upvotes: 1

Related Questions