Selecting and inserting text at cursor location in textfield with JS/jQuery
- by IceCreamYou
Hello.
I have developed a system in PHP which processes #hashtags like on Twitter. Now I'm trying to build a system that will suggest tags as I type. When a user starts writing a tag, a drop-down list should appear beneath the textarea with other tags that begin with the same string.
Right now, I have it working where if a user types the hash key (#) the list will show up with the most popular #hashtags. When a tag is clicked, it is inserted at the end of the text in the textarea. I need the tag to be inserted at the cursor location instead. Here's my code; it operates on a textarea with class "facebook_status_text" and a div with class "fbssts_floating_suggestions" that contains an unordered list of links. (Also note that the syntax [#my tag] is used to handle tags with spaces.)
maxlength = 140;
var dest = $('.facebook_status_text:first');
var fbssts_box = $('.fbssts_floating_suggestions');
var fbssts_box_orig = fbssts_box.html();
dest.keyup(function(fbss_key) {
if (fbss_key.which == 51) {
fbssts_box.html(fbssts_box_orig);
$('.fbssts_floating_suggestions .fbssts_suggestions a').click(function() {
var tag = $(this).html();
//This part is not well-optimized.
if (tag.match(/W/)) {
tag = '[#'+ tag +']';
}
else {
tag = '#'+ tag;
}
var orig = dest.val();
orig = orig.substring(0, orig.length - 1);
var last = orig.substring(orig.length - 1);
if (last == '[') {
orig = orig.substring(0, orig.length - 1);
}
//End of particularly poorly optimized code.
dest.val(orig + tag);
fbssts_box.hide();
dest.focus();
return false;
});
fbssts_box.show();
fbssts_box.css('left', dest.offset().left);
fbssts_box.css('top', dest.offset().top + dest.outerHeight() + 1);
}
else if (fbss_key.which != 16) {
fbssts_box.hide();
}
});
dest.blur(function() {
var t = setTimeout(function() { fbssts_box.hide(); }, 250);
});
When the user types, I also need get the 100 characters in the textarea before the cursor, and pass it (presumably via POST) to /fbssts/load/tags. The PHP back-end will process this, figure out what tags to suggest, and print the relevant HTML. Then I need to load that HTML into the .fbssts_floating_suggestions div at the cursor location.
Ideally, I'd like to be able to do this:
var newSuggestions = load('/fbssts/load/tags', {text: dest.getTextBeforeCursor()});
fbssts_box.html(fbssts_box_orig);
$('.fbssts_floating_suggestions .fbssts_suggestions a').click(function() {
var tag = $(this).html();
if (tag.match(/W/)) {
tag = tag +']';
}
dest.insertAtCursor(tag);
fbssts_box.hide();
dest.focus();
return false;
});
And here's the regex I'm using to identify tags (and @mentions) in the PHP back-end, FWIW.
%(\A(#|@)(\w|(\p{L}\p{M}?))+\b)|((?<=\s)(#|@)(\w|(\p{L}\p{M}?))+\b)|(\[(#|@).+?\])%u
Right now, my main hold-up is dealing with the cursor location. I've researched for the last two hours, and just ended up more confused. I would prefer a jQuery solution, but beggars can't be choosers.
Thanks!