Place tags around certain text within contenteditable without moving cursor
Asked Answered
M

1

1

I am working on a simple (I thought) word processor. It uses contenteditable. I have a list of words that I want to always appear highlighted.

<article contenteditable="true" class="content">
    <p>Once upon a time, there were a couple of paragraphs. Some things were <b>bold</b>, and other things were <i>italic.</i></p>
    <p>Then down here there was the word highlight. It should have a different color background.</p>
</article>

So basically what I need is a way to wrap a word in <span> tags. This has proven more difficult than I expected.

Here was what I tried first:

var text = document.querySelector('article.content').innerHTML
    start = text.indexOf("highlight"),
    end = start + "highlight".length;
text = text.splice(end, 0, "</span>");
text = text.splice(start, 0, "<span>");
document.querySelector('article.content').innerHTML = text;

It uses the splice method found here.

And it does exactly what I need it to do, with one big issue: the cursor gets moved. Because all the text is replaced, the cursor loses its place, which isn't a good thing for a text editor.

I've also tried a couple times using document.createRange, but the issue is that while given the start and end points of a range only includes visible characters, text.indexOf("highlight") gives the index including the tags and such.

A few ideas which I'm not sure how to execute:

  • Figure out where the cursor begins and place it there again after using the code above
  • Find the difference in indexes between createRange and indexOf
  • Maybe there's already a library with this kind of functionality that I just can't find

Thank you for your help!

Mystic answered 10/7, 2014 at 17:24 Comment(0)
I
1

Firstly, I would recommend against doing this by manipulating innerHTML. It's inefficient and error-prone (think of the case where the content contains an element with a class of "highlight", for example). Here's an example of doing this using DOM methods to manipulate the text nodes directly:

https://mcmap.net/q/1020395/-highlighting-text-in-document-javascript-efficiently

Maintaining the caret position can be achieved a number of ways. You could use a character offset-based approach, which has some disadvantages due to not considering line breaks implied by <br> and block elements but is relatively simple. Alternatively, you could use the selection save and restore module of my Rangy library, which may be overkill for your needs, but the same approach could be used.

Here is an example using the first approach:

http://jsbin.com/suwogaha/1

Illogicality answered 10/7, 2014 at 23:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.