1

I'm trying to create an editable div that regularly checks for any text that was typed that matches @text (starts with @ and ends with a space).

So for example, if the user were to type @text more text here, it would change the word that starts with @ and ends with a space to a link like <a href="#">@text</a> more text here within the div.

I've started with JSFiddle, however, I can't get it working: http://jsfiddle.net/MpFXK/2/

HTML:

<div class="box" contenteditable="true"></div>

JS:

$(document).on('keyup', ".box", function() {
    var text = $(this).text();
    var regexp = /\B@([^\B ]+)/;
    if (text.match(regexp)) {      
        text = text.replace(/\B@([^\B ]+)/, '<a href="#">/\B@([^\B ]+)/</a> ');
        return $(this).html(text);
    }
    return false;
});

Please help!

Bagwell
  • 2,018
  • 5
  • 18
  • 24
  • You forgot to include jQuery in your jsFiddle, also `\B` is the opposite of `\b`, it doesn't match word boundary. Replacing HTML will reset text cursor position and break undo history. Also when you get this working you should check for already replaced `@text`, to avoid wrapping it in a link over and over. – Alexey Lebedev Dec 16 '13 at 23:40
  • Also placing `\B` in a character class won't do what you expect it to do. – Qantas 94 Heavy Dec 17 '13 at 00:23

2 Answers2

2

fiddle

$(document).on('keyup', ".box", function(e) {
    if (e.keyCode == 32) {
        var text = $(this).text();
        var regexp = /(?=[@])[*@]\w+/;

        var newText = text.replace(regexp, function(match) {
            return '<a href="#">' + match + '</a>'
        });
        $(this).html(newText);
        setEndOfContenteditable(this);
    }
});

function setEndOfContenteditable(contentEditableElement)
{
    var range,selection;
    if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+
    {
        range = document.createRange();//Create a range (a range is a like the selection but invisible)
        range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range
        range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
        selection = window.getSelection();//get the selection object (allows you to change selection)
        selection.removeAllRanges();//remove any selections already made
        selection.addRange(range);//make the range you have just created the visible selection
    }
    else if(document.selection)//IE 8 and lower
    { 
        range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible)
        range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range
        range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
        range.select();//Select the range (make it the visible selection
    }
}

credit for setEndOfContenteditable function

Community
  • 1
  • 1
Tomanow
  • 7,247
  • 3
  • 24
  • 52
  • Unfortunately (this is close!) if you move back to half way through a line of text and enter @something - the cursor shoots to the end randomly. And if you start typing on a new line - the lines are joined together and all sorts of strange things happen. – Ian Sep 08 '16 at 10:16
1

This should get you what you're asking for, if I understand the question correctly.

http://jsfiddle.net/MpFXK/4/

$(document).on('keyup', ".box", function(e) {
var text = $(this).html();
var firstAt = text.indexOf('@');

if(e.keyCode === 32 && firstAt > -1) {
    var textToReplace = text.substring(firstAt, text.len);
    //alert(textToReplace);
    var newText = "<a href='#'>" + textToReplace.substring(1, textToReplace.len) + "</a>";
    //alert(newText);
    var complete = text.replace(textToReplace, newText);
    //alert(complete);
    $(this).html(complete);        
    placeCaretAtEnd($(this).get(0));
}

});

function placeCaretAtEnd(el) {
el.focus();
if (typeof window.getSelection != "undefined"
        && typeof document.createRange != "undefined") {
    var range = document.createRange();
    range.selectNodeContents(el);
    range.collapse(false);
    var sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);
} else if (typeof document.body.createTextRange != "undefined") {
    var textRange = document.body.createTextRange();
    textRange.moveToElementText(el);
    textRange.collapse(false);
    textRange.select();
}

}

A few notes to go along with it:

  • On every keyup, you look for an '@' and whether or not the key just pressed is a space (32). At that point you have your word to replace (based upon your criteria above).
  • This uses html() instead of text() which is important. If you use text() you will end up replacing all of your previous anchor tags.
  • placeCaretAtEnd is directly from this SO post: enter link description here
Community
  • 1
  • 1
James Wilson
  • 290
  • 3
  • 10