3

Possible Duplicate:
Inserting a text where cursor is using Javascript/jquery

I'm building a simple templating system here. Basically I've set up buttons that add preset variables into a textarea.

The thing is that I want to be able to add text in my textarea at the position where my cursor is. Just like when you click on the URL link in the editor window for posts here at stackoverflow the link is added at the position where your cursor is.

How can I do that? And can it be done using prototype JS?

Community
  • 1
  • 1
Ali
  • 7,353
  • 20
  • 103
  • 161

1 Answers1

5

It's a bit tricky in IE, which does an exceptionally bad job of this kind of thing. The following will insert text at the end of the current selection in a textarea or text input (or at the caret if the no text is selected) and then position the cursor after the text:

Demo: http://jsfiddle.net/RqTvT/1/

Code:

function getInputSelection(el) {
    var start = 0, end = 0, normalizedValue, range,
        textInputRange, len, endRange;

    if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
        start = el.selectionStart;
        end = el.selectionEnd;
    } else {
        range = document.selection.createRange();

        if (range && range.parentElement() == el) {
            len = el.value.length;
            normalizedValue = el.value.replace(/\r\n/g, "\n");

            // Create a working TextRange that lives only in the input
            textInputRange = el.createTextRange();
            textInputRange.moveToBookmark(range.getBookmark());

            // Check if the start and end of the selection are at the very end
            // of the input, since moveStart/moveEnd doesn't return what we want
            // in those cases
            endRange = el.createTextRange();
            endRange.collapse(false);

            if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
                start = end = len;
            } else {
                start = -textInputRange.moveStart("character", -len);
                start += normalizedValue.slice(0, start).split("\n").length - 1;

                if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
                    end = len;
                } else {
                    end = -textInputRange.moveEnd("character", -len);
                    end += normalizedValue.slice(0, end).split("\n").length - 1;
                }
            }
        }
    }

    return {
        start: start,
        end: end
    };
}

function offsetToRangeCharacterMove(el, offset) {
    return offset - (el.value.slice(0, offset).split("\r\n").length - 1);
}

function setSelection(el, start, end) {
    if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
        el.selectionStart = start;
        el.selectionEnd = end;
    } else if (typeof el.createTextRange != "undefined") {
        var range = el.createTextRange();
        var startCharMove = offsetToRangeCharacterMove(el, start);
        range.collapse(true);
        if (start == end) {
            range.move("character", startCharMove);
        } else {
            range.moveEnd("character", offsetToRangeCharacterMove(el, end));
            range.moveStart("character", startCharMove);
        }
        range.select();
    }
}

function insertTextAtCaret(el, text) {
    var pos = getInputSelection(el).end;
    var newPos = pos + text.length;
    var val = el.value;
    el.value = val.slice(0, pos) + text + val.slice(pos);
    setSelection(el, newPos, newPos);
}

var textarea = document.getElementById("your_textarea");
insertTextAtCaret(textarea, "[INSERTED]");
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • Sadly, this breaks in Chrome (Version 28.0.1500.52) with `Uncaught TypeError: Object # has no method 'createTextRange' `. The text is inserted, but the position of the cursor afterwards is screwed up. – Polygnome Jun 22 '13 at 10:47
  • @Polygnome: Ah yes, some oversights there. Oops. Updated now. – Tim Down Jun 22 '13 at 13:27