0

My example:

<div contenteditable="true">
    Hello <span class="tagname">Hermione</span> hello @
</div>

When I get the text of the div:

let text = $('[contenteditable=true]').text(); // 'Hello Hermione hello @'

The index of @ character is: 21.

I want to insert more span tag inside the div via the index. But how can I do that without losing already tag(s)?

My idea:

let $div = $('[contenteditable=true]'), text = $div.text(), 
    tagname = $('<span>').addClass('tagname').text('voldemort');

$div.html(text.substring(0, index))
    .append(tagname)
    .append(text.substring(index + 1, text.length));

If I use that way, all already tag(s) would be overridden. I will lose them.

Also, I cannot use:

$div.html($div.html().replace('@', tagname[0].innerHTML));

because the content may contain some @ character(s) that I don't want to replace (must be via index).

Any idea about this problem?

Tân
  • 1
  • 15
  • 56
  • 102
  • What do you want your final $div to look like specifically? – wlh Feb 11 '17 at 17:57
  • @wlh My goal: `Hello Hermione hello voldemort` – Tân Feb 11 '17 at 17:58
  • Could you use your final example (I'm assuming the @ will be the last item in the string) with the following regex? `$div.html($div.html().replace(/@$/, tagname[0].innerHTML));` – wlh Feb 11 '17 at 18:05
  • If it is possible to have other `@` use a different delimiter that user is not likely to use. Or if there are more than one give user the choice what to replace – charlietfl Feb 11 '17 at 18:08
  • Here is a discussion on using regex to find a particular character at a particular index - http://stackoverflow.com/questions/34789929/regex-to-match-character-in-specific-position – wlh Feb 11 '17 at 18:11
  • @charlietfl I've tried to split `` and `<\/span>` to some blocks before replacing but I still don't know how to connect them correct position. – Tân Feb 11 '17 at 18:17
  • @wlh Sorry but `@` character can be found in first/middle/last string. Not at last at all. – Tân Feb 11 '17 at 18:18
  • Can the one you need to replace be made to always be set inside a span with a class when it is created? – charlietfl Feb 11 '17 at 18:25
  • @charlietfl Yes. the span contains a class with specific css (`background-color: lightblue;`). That's the difference from another text in the div. – Tân Feb 11 '17 at 18:39

1 Answers1

1

You have to find a mechanism to always get the @ index to make sure it is the character index you actually want.

You can then use slice as follows:

var html = $('[contenteditable=true]').html(); 

// get the index of the character you need to replace
var idx = html.indexOf("@");

// create the tagname
var tagname = $('<span>').addClass('tagname').text('voldemort');

// slice the existing html content, skip the @, 
// and include the outerhtml of the tagname
var txt2 = html.slice(0, idx) + tagname[0].outerHTML + html.slice(idx + 1);

// set the html of the content editable with the replaced character
$('[contenteditable=true]').html(txt2);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div contenteditable="true">
    Hello <span class="tagname">Hermione</span> hello @
</div>

EDIT

If you can actually tell what is the occurrence number of the @ character you want to replace in the string, you use this method in the below answer:

https://stackoverflow.com/a/14480366/2611451:

function getPosition(string, subString, index) {
   return string.split(subString, index).join(subString).length;
}
Community
  • 1
  • 1
KAD
  • 10,972
  • 4
  • 31
  • 73
  • Thank you! I think the problem came from the way I get the index of `@` character. `html.indexOf("@")` is true almost case, but since I've 2 or more `@` characters and want to replace one of them (not the first), it's wrong. But, thanks! – Tân Feb 11 '17 at 18:37
  • How do you specify which `@` character you are gonna replace? What factor says it is the first or second or .... n? – KAD Feb 11 '17 at 18:39
  • My question may unclear a bit, sorry about that. When keydown event detects `@` character, a list with some user names will be display, if one of them is click, the name will be insert into div. I worry that user presses `@` but he doesn't click any name, then, continues entering `@` character but clicking a name. – Tân Feb 11 '17 at 18:45
  • Couldn't you just replace the `@` at the index where the user is currently typing, I bet it is always the end of the string in your case. Even if the user skips an `@`, he cannot replace it unless he is at its level in typing. – KAD Feb 11 '17 at 18:49
  • I've an idea about your update: Find the index of `@` first, count number of `@` in the substring `text.substring(0, index)`. Then, I will have `@`'s nth that I want to replace. Last, using your update answer. Right? – Tân Feb 11 '17 at 18:53
  • mmm, I didn't get that much, but it is always worth a try now while having better tools now in hand :) – KAD Feb 11 '17 at 18:56
  • Ya, thanks for advice `use a plugin`. I don't think there are many `better tools` support autocomplete with contenteditable instead of textarea/input. I've found 1 plugin, that's [algolia](https://www.algolia.com/doc/guides/search/autocomplete-textarea/). But it's not free at all and not easy to use. – Tân Feb 11 '17 at 19:01
  • You can tune your code to cover this functionality with minimal time and conserve some of the features, or if you think you have the time, you can dig into all this and create a detailed content editable auto complete plugin – KAD Feb 11 '17 at 19:15
  • Thanks for conversation. That's help! – Tân Feb 11 '17 at 19:21