19

Okay, I've been looking all over the web to find a solution but I couldn't find one, is there a way to get the word before the caret position in an editable div so a bit like:

This is some| demo texts

This should return the word "some"... I don't know if this is possible, I would be glad for any help, thanks :).

General Grievance
  • 4,555
  • 31
  • 31
  • 45
Lennart
  • 1,560
  • 5
  • 20
  • 38

3 Answers3

24

With using Caret Position finder method provided here this will do what you want.

function ReturnWord(text, caretPos) {
    var index = text.indexOf(caretPos);
    var preText = text.substring(0, caretPos);
    if (preText.indexOf(" ") > 0) {
        var words = preText.split(" ");
        return words[words.length - 1]; //return last word
    }
    else {
        return preText;
    }
}

function AlertPrevWord() {
    var text = document.getElementById("textArea");
    var caretPos = GetCaretPosition(text)
    var word = ReturnWord(text.value, caretPos);
    if (word != null) {
        alert(word);
    }

}

function GetCaretPosition(ctrl) {
    var CaretPos = 0;   // IE Support
    if (document.selection) {
        ctrl.focus();
        var Sel = document.selection.createRange();
        Sel.moveStart('character', -ctrl.value.length);
        CaretPos = Sel.text.length;
    }
    // Firefox support
    else if (ctrl.selectionStart || ctrl.selectionStart == '0')
        CaretPos = ctrl.selectionStart;
    return (CaretPos);
}
<input id="textArea" type="text" />
<br />
<input id="Submit" type="submit" value="Test" onclick="AlertPrevWord()" />

Here is also a jsfiddle.

Basj
  • 41,386
  • 99
  • 383
  • 673
Özgür Kaplan
  • 2,106
  • 2
  • 15
  • 26
  • Could please make a jsfiddle? Cause I don't know how to implement this into a textarea... – Lennart Mar 31 '12 at 21:49
  • By `|` the OP meant caret position, not the actual vertical line character present in source string. – Dmitry Pashkevich Mar 31 '12 at 21:54
  • @Dmitry Pashkevich Updated my answer – Özgür Kaplan Mar 31 '12 at 22:28
  • This is pretty much what I want, but I can't get this to work in a contenteditable div and I'm not sure why??? I changed the `.value` to `.innerHTML` – Lennart Apr 01 '12 at 07:49
  • @Lenny if you replace ctrl.value and text.value with ctrl.innerText & text.innerText than it works in IE. Don't know the solution for Firefox. div.selectionStart returns undefined. – Özgür Kaplan Apr 01 '12 at 11:05
  • yeh I've realised that the above code for finding the cursor position isn't working in firefox but I can't find a way to get it to work... I think I'm gonna have to find a work around for what I'm trying to do :) but cheers for the hard work ;) – Lennart Apr 01 '12 at 20:32
  • great great great. you made my day. wish i could upvote this hundred times :D – Ali Nov 19 '13 at 11:52
  • This doesn't seems to be working well with spaces. However, gives a clear idea about the solution. – Zerotoinfinity Dec 26 '14 at 10:08
  • `index` is not used in `ReturnWord` and also when looking for `preText.indexOf(" ")` we don't into account new line character – Omu Feb 13 '18 at 06:31
10

Here is a rough method using the Selection and Range objects.

function getWord() {
    var range = window.getSelection().getRangeAt(0);
    if (range.collapsed) {
        text = range.startContainer.textContent.substring(0, range.startOffset+1);
        return text.split(/\b/g).pop();
    }
    return '';
}

You can see it in action here: http://jsfiddle.net/ggfFw/1/. This will not work in IE. If you need IE support look at the Rangy library.

Hemlock
  • 6,130
  • 1
  • 27
  • 37
3

I had something like that https://stackoverflow.com/a/9960262/986160 yet at some point it wasn't getting a selection in my Chrome browser. Based on my other answer here: https://stackoverflow.com/a/26728677/986160 - I changed it accordingly to be:

function getLastWordBeforeCaret() {
    const containerEl = document.getElementById('element-id');
    let preceding = '';
    let sel;
    let range;
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel && sel.rangeCount > 0) {
            range = sel.getRangeAt(0).cloneRange();
            range.collapse(true);
            range.setStart(containerEl, 0);
            preceding = range.toString();
        }
    }
    let queryMatch = preceding.match(/([^\s]+)$/i);
    if (queryMatch) {
        return queryMatch[1];
    } else {
        return '';
    }
}
Michail Michailidis
  • 11,792
  • 6
  • 63
  • 106
  • 1
    Great solution but this will leave out the character just before the cursor. will fix and post edit. – SSED Sep 11 '18 at 09:36