8

How can I get a word in textarrea by its current caret position?

I tried something like this, however this returns just the words first letter upto the character at caret position. For example:

if the cursor is between fo and o it returns fo and not foo as excpected.

Fo|o bar is not equal to bar foo. => Fo expects Foo

Foo bar is not equ|al to bar foo. => equ expects equal.

Here's what I've done so far:

function getCaretPosition(ctrl) {
    var start, end;
    if (ctrl.setSelectionRange) {
        start = ctrl.selectionStart;
        end = ctrl.selectionEnd;
    } else if (document.selection && document.selection.createRange) {
        var range = document.selection.createRange();
        start = 0 - range.duplicate().moveStart('character', -100000);
        end = start + range.text.length;
    }
    return {
        start: start,
        end: end
    }
}

$("textarea").keyup(function () {
    var caret = getCaretPosition(this);

    var result = /\S+$/.exec(this.value.slice(0, caret.end));
    var lastWord = result ? result[0] : null;
    alert(lastWord);
});

http://fiddle.jshell.net/gANLv/

yckart
  • 32,460
  • 9
  • 122
  • 129

3 Answers3

6

Try change this line in your code to this:

 var result = /\S+$/.exec(this.value.slice(0, this.value.indexOf(' ',caret.end)));
Steve Butabi
  • 96
  • 1
  • 3
  • 1
    This is awesome works for me too. The only problem is that last word in the text will cut the last character if there is no space at the end of the text... For example `This is dome text` would return `tex` if the cursor is at the end. And `This is dome text ` would return properly `text`. Can this be fixed? – Primoz Rome Oct 01 '16 at 16:56
  • 1
    Added a version that handles last word in textarea and removes trailing puntuation http://stackoverflow.com/a/40338359/295783 – mplungjan Oct 31 '16 at 08:16
  • 9 years later and you're still a god, thank you so much! – David Rearte Sep 09 '22 at 21:09
1

Stumbled accross this looking for a vanilla JS answer and ended up writing one. Here is a relatively safe utility function that will work on all modern browsers (you can pass in any node or call it without any args to default to document.activeElement).

Note that this method can return undefined, zero, or N length whitespace strings:

  • given a selection like this " " a 2 length whitespace string would be returned
  • given no selection and no caret is on the page (i.e. a textarea is not focused) undefined would be returned
  • given a caret inside a textarea that is not at the start/end/within a word, a zero length string would be returned
  • given a caret inside a textarea that is at the start/end/within a word, that word (including punctuation and special chars) would be returned
// returns the current window selection if present, else the current node selection if start and end
// are not equal, otherwise returns the word that has the caret positioned at the start/end/within it
function getCurrentSelection (node = document.activeElement) {
  if (window.getSelection().toString().length > 0) {
    return window.getSelection().toString()
  }

  if (node && node.selectionStart !== node.selectionEnd) {
    return node.value.slice(node.selectionStart, node.selectionEnd)
  }

  if (node && node.selectionStart >= 0) {
    const boundaries = {
      start: node.selectionStart,
      end: node.selectionStart
    }
    const range = document.createRange()
    range.selectNode(node)
    const text = range.cloneContents().textContent
    if (text) {
      let i = 0
      while (i < 1) {
        const start = boundaries.start
        const end = boundaries.end
        const prevChar = text.charAt(start - 1)
        const currentChar = text.charAt(end)

        if (!prevChar.match(/\s/g) && prevChar.length > 0) {
          boundaries.start--
        }

        if (!currentChar.match(/\s/g) && currentChar.length > 0) {
          boundaries.end++
        }

        // if we haven't moved either boundary, we have our word
        if (start === boundaries.start && end === boundaries.end) {
          console.log('found!')
          i = 1
        }
      }
      return text.slice(boundaries.start, boundaries.end)
    }
  }
}

GrayedFox
  • 2,350
  • 26
  • 44
  • The reason the length check is there is because, at least on Firefox, I ran into a bug where the current/previous character was not considered whitespace and yet had a length of 0 (weird). Length check saved the while loop from going infinite. – GrayedFox Sep 18 '19 at 17:42
0
val = input.value.split(" ");
last_word = val.length > 0 ? val[val.length-1] : val[0];
console.log(last_word);
Arup
  • 131
  • 5