2

http://jsfiddle.net/m45uM/

The replacement with the a tag works fine, but it sets me to the first position inside the editable div then.

How can i fix this? And how can I trigger an event that i'm currently havin my caret placed inside an a tag like twitter does?

function replacer(match, p1, p2, p3, offset, string) {
    var name = '';
    var user = '';
    $.each(ar.data, function (i, item) {
        var keyword = match.substring(1, (match.length - 1));
        if (keyword == item.name) {
            user = item.user;
            name = item.name;
        }
    });
    return '<a href="/' + user + '">' + name + '</a>';
}
$(document).ready(function (e) {
    $('body').on('keyup', '#cont', function (e) {
        var cont = $('#cont').html();
        var cont2 = cont.replace(/\@\w+\s/gi, replacer);
        $('#cont').html(cont2);
        console.log($('#cont').html());
    });
});
var ar = {
    "data": [{
        "user": "testuser1",
            "name": "testname1"
    }, {
        "user": "testuser2",
            "name": "testname2"
    }]
};
console.log(ar);
j08691
  • 204,283
  • 31
  • 260
  • 272
  • possible duplicate of [Javascript: Move caret to last character](http://stackoverflow.com/questions/4715762/javascript-move-caret-to-last-character) – epascarello Aug 16 '13 at 13:19
  • 2
    it is not a duplicate. Take a look, i'm using a div editable, the link refers to a text box! –  Aug 16 '13 at 13:20
  • Should have been this one: http://stackoverflow.com/questions/1181700/set-cursor-position-on-contenteditable-div – epascarello Aug 16 '13 at 13:40
  • @epascarello This code doesn't work. It throws out an error that onkeyup is null. –  Aug 16 '13 at 13:46
  • For textareas this is easy but in editable divs its hard to get it to work while keeping it working on all browsers. – astroanu Aug 17 '13 at 16:43
  • 1
    @AnuradhaJayathilaka but how does twitter make it? –  Aug 17 '13 at 17:56
  • good question. ;D after a lot of head banging i went for a solution similar to epascarello's answer. but still there are bugs. – astroanu Aug 21 '13 at 11:36

1 Answers1

0

A couple of things before I have an attempt at this:

  1. Please do not add elements into the dom as strings - "return ..". You'll have a hard time performing other actions with this node. Instead I suggest, you use DOM APIs (create/remove/replace/append/etc) to perform these functions. My suggestion will be clear as you read through.

  2. You return a new string and you blindly set the HTML to that particular string - you are losing all the text before it. Example: Hello my name is @testuser1 becomes only @ - you lose "Hello my name is"

Solution:

To take care of carrot placements, you have to remember the selection of the user. Note - if you change the HTML, the browser will lose this selection; hence, you need to track this manually.

Before you 'replace' the text, you can get the selection by:

//IE & Others
if (window.getSelection) {
    userSelection = window.getSelection();
} else if (document.selection) {
    userSelection = document.selection.createRange();
}
selectedNode = userSelection.anchorNode;
selectedOffset = userSelection.anchorOffset;

After you replace the text, you need to set the selection back to the container.

//IE & Others


var range,
        selection;
    if (window.getSelection) {
        selection = window.getSelection();
        range = document.createRange();
        range.setStart(targetElement, targetOffset);
        range.setEnd(targetElement, targetOffset);
        selection.removeAllRanges();
        selection.addRange(range);
    } else if (document.selection) {
        range = document.selection.createRange();
        range.moveToElementText(targetElement.parentElement);
        range.collapse(true);
        range.moveEnd('character', targetOffset);
        range.moveStart('character', targetOffset);
        range.select();
    }
}

The target Element and the target offset is the node you want to target and the postion (from the left) you want the cursor to be.

Now that the basics are over, here comes the hard part:

  • When you break up the text (TextNode) by putting in an anchor element, you need to have the target element as the anchor element and the offset to be the length of the text inside the anchor element. This would be much easier if you use DOM APIs and store this element as a variable.

  • You need to cater to situations where the user might go to any part of the text and enter @username1; this should be fairly simple.

You could also play around with Rangy JS lib to achieve this.

Have fun!

Gautam Bhutani
  • 395
  • 2
  • 12