views:

219

answers:

3

I'm allowing the user to select text contained within <div></div> and change it to bolded text. In other words from <div>this is some text</div> to <div>this is <b>some</b> text</div>. All is working except that when I change the div.innerHTML to this is <b>some</b> text, the <b>some</b> tags are shown to the user rather than being rendered as HTML and displaying some bolded. This is all happening client side with Javascript.

How do I force the browser to render the tags rather than reveal them to the user?

Per request, here is the code...

HTML...

<div id="blob">
One simple, but not very efficient implementation of a dictionary is a linked 
list. In this implementation all operations take linear time in the worst case 
(and even in the average case), assuming that insertions first check whether the 
item is in the current list. A more scalable implementation of a dictionary is a 
balanced search tree. In this lecture note we present two even more efficient data 
structures based on hashing.
</div>

Javascript...

tagText(document.getElementById("blob"),"<b>","</b>");

and...

//======================================================================
function tagText(el,tagstart,tagend)
    {
    var range = window.getSelection().getRangeAt(0);
    var rtxt = range.startContainer.textContent;
    var rlen = rtxt.length;
    var start = range.startOffset;
    var stop = range.endOffset;
    var result = rtxt.substring(0,start) + tagstart + rtxt.substring(start,stop) + tagend + rtxt.substring(stop,rlen);
//  el.innerHTML = result;
    range.startContainer.textContent = result;
    var txt = el.innerHTML;
    el.innerHTML = txt;
    }
//======================================================================


Looking at the div:innerHTML via firebug shows that the tags are escaped &lt;b&gt; rather than <b>.

+3  A: 

That's not what's causing your problem, but.. Isn't this wrong?

var txt = el.innerHTML;
el.innerHTML = txt;

Edit:

Try this:

<div id="blob">
One simple, but not very efficient implementation of a dictionary is a linked 
list. In this implementation all operations take linear time in the worst case 
(and even in the average case), assuming that insertions first check whether the 
item is in the current list. A more scalable implementation of a dictionary is a 
balanced search tree. In this lecture note we present two even more efficient data 
structures based on hashing.
</div>

<input type="button" value="sample" onclick='tagText();'>

and...

<script>
  function tagText() {
    var range = window.getSelection().getRangeAt(0);
    range.surroundContents(document.createElement("b"));
  }
</script>
Carlos Lima
I agree, it is silly. But I was trying to somehow force a re-rendering of the HTML.
dacracot
Updated. Check if it works for you.
Carlos Lima
Awesome, thank you.
dacracot
Happy to help! :)
Carlos Lima
A: 

In jQuery, that'd be $('#blob').wrap('<b></b>');. You don't even need to write a helper function then. Seriously, use a library. Don't waste your time figuring out low-level stuff.

Randal Schwartz
I want to wrap a specific word, not the entire div. And the library comment isn't helpful.
dacracot
+2  A: 

I believe the problem is this line:

range.startContainer.textContent = result;

You aren't actually setting the innerHTML of the div element, you are setting the text of the container of the range, which will not interpret tags as HTML. Instead, try setting the inner HTML of the div directly from your results and clear the range.

For clarrification - this code will actually conver the selected content to bold.

var rtxt = range.startContainer.textContent;
var rlen = rtxt.length;
var start = range.startOffset;
var stop = range.endOffset;
var result = rtxt.substring(0,start) + tagstart + rtxt.substring(start,stop) + tagend + rtxt.substring(stop,rlen);
el.innerHTML = result;

If you want to maintain the selection then you will need to programtically reset the range.

James Conigliaro
Good try... but on the second and subsequent calls to tagText the range.startContainer.textContent will become smaller as tags are added and only the text between them is returned.
dacracot
@dacracot: That's actually another issue. You're fetching the text only and expecting results on the HTML to match correctly.
Carlos Lima
@dacrocat, I'm not sure if I undstand your comment. Ive edited my response for further clarrification.
James Conigliaro
@James - This works on the first iteration only. Select a word, execute the script, and you get bolding. Select a second word, execute the script, and the text is totally munged.
dacracot
That is becuase you the parent element now contains HTML instead of just pure text which is changing the value of the .startContainer attribute. See the soluton provided by @Carolos - it appears to work well.
James Conigliaro