Get current word on caret position
Asked Answered
N

3

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/

Nescience answered 24/3, 2013 at 16:1 Comment(0)
W
6

Try change this line in your code to this:

 var result = /\S+$/.exec(this.value.slice(0, this.value.indexOf(' ',caret.end)));
Winburn answered 24/3, 2013 at 16:26 Comment(3)
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?Gilbertine
Added a version that handles last word in textarea and removes trailing puntuation https://mcmap.net/q/1469716/-get-occurence-between-and-textarea-current-positionTriboelectricity
9 years later and you're still a god, thank you so much!Southward
T
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)
    }
  }
}

Tyrr answered 18/9, 2019 at 17:38 Comment(1)
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.Tyrr
M
0
val = input.value.split(" ");
last_word = val.length > 0 ? val[val.length-1] : val[0];
console.log(last_word);
Moorefield answered 7/6, 2021 at 9:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.