15

I am about to implement Facebook like in integration in my contenteditable div where if i give '$' and some character like 'a' i need a auto-suggestion which should pop up near my caret position.

I need to know how to find out the last character before caret position either in JavaScript for IE and Other browsers. I have access to the Jquery library.

(function($) {
    $.fn.getCursorPosition = function() {
        var input = this.get(0);
        if (!input) return; // No (input) element found
        if ('selectionStart' in input) {
            // Standard-compliant browsers
            return input.selectionStart;
        } else if (document.selection) {
            // IE
            input.focus();
            var sel = document.selection.createRange();
            var selLen = document.selection.createRange().text.length;
            sel.moveStart('character', -input.value.length);
            return sel.text.length - selLen;
        }
    }
})(jQuery);

eg.
var caretPosition = $("#contenteditablediv").getCursorPosition();
var lastchar = getchar(caretposition -1);???
Anoop
  • 849
  • 3
  • 13
  • 28
  • 1
    That function won't work for contenteditable elements in non-IE browsers. it's for inputs and textareas. – Tim Down Mar 01 '13 at 12:14
  • yes i know it was just a example.. can you suggest me some other way to find the last character before caret position?? – Anoop Mar 01 '13 at 12:17

1 Answers1

29

Here's an example of how to do this. It creates a range that starts at the start of the editable element and ends immediately before the caret, gets the range's text and returns the last character of that range.

Demo: http://jsfiddle.net/MH5xX/

function getCharacterPrecedingCaret(containerEl) {
    var precedingChar = "", sel, range, precedingRange;
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.rangeCount > 0) {
            range = sel.getRangeAt(0).cloneRange();
            range.collapse(true);
            range.setStart(containerEl, 0);
            precedingChar = range.toString().slice(-1);
        }
    } else if ( (sel = document.selection) && sel.type != "Control") {
        range = sel.createRange();
        precedingRange = range.duplicate();
        precedingRange.moveToElementText(containerEl);
        precedingRange.setEndPoint("EndToStart", range);
        precedingChar = precedingRange.text.slice(-1);
    }
    return precedingChar;
}

var editableEl = document.getElementById("editable");
var precedingCharEl = document.getElementById("precedingChar");

function reportCharacterPrecedingCaret() {
    precedingCharEl.innerHTML = "Character preceding caret: " + getCharacterPrecedingCaret(editableEl);
}

editableEl.onmouseup = editableEl.onkeyup = reportCharacterPrecedingCaret;
<div contenteditable="true" id="editable">Here is some text. Please put the caret somewhere in here.</div>
<div id="precedingChar" style="font-weight: bold"></div>
Elazar
  • 20,415
  • 4
  • 46
  • 67
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • 1
    hi its works like a charm. Thanks. I have got one more problem. I am using Infragistics content-Editor. So in IE it will be a div but in Chrome it will be a iframe. I tried with iframe and its not working.. can you tell me how will i find it in iframe.Thanks – Anoop Mar 01 '13 at 12:56
  • @Anoop: You'll need to replace the references to `document` and `window` with document and window objects obtained from the iframe. Shouldn't be too hard. – Tim Down Mar 01 '13 at 15:48
  • Thanks.It worked for me.For Chrome with Iframe i used document.getElementById('iframe_id').contentDocument.getSelection() instead of window.getSelection. And i used range.setStart(containerEl.contentDocument.body, 0); insead of range.setStart(containerEl, 0);Thanks once again. can u suggest me any solution for this link [how to show an auto suggestion div near the caret position in a content-editable div](http://stackoverflow.com/questions/15159692/how-to-show-an-auto-suggestion-div-near-the-caret-position-in-a-content-editable) – Anoop Mar 02 '13 at 05:56
  • 4
    Hopefully someone else could find this useful such as I did for finding the character immediately after the caret. Many thanks to @TimDown for his extra help http://jsfiddle.net/MH5xX/139/ – scniro Jun 30 '14 at 14:40
  • @scniro it seem I found a solution for getting character after the caret: you just need to use `range.setEndAfter(range.endContainer)` instead of `range.setStart(containerEl, 0)` and then get first character of this range: `range.toString()[0]` – Legotin Apr 08 '18 at 13:17
  • Looking for this for weeks ! Thank you Tim ;) – Amadou Beye Nov 23 '18 at 08:46