I have to convert user entered unordered lists in a content management system into a bootstrap menu (navbar) using jquery.
80% there apart from one challenge that I can't figure out a nice solution for - ie one that uses selectors rather than string manipulation or regex. After all, we all know that we never parse html with regex :)
So, using the limited UI tools at the user's disposal, they generate a list, usually a two level nested list something like this
<ul>
 <li>Blah1
  <ul>
   <li><a href='http://xxxx'>Blah1a</a></li>
   <li><a href='http://yyyy'>Blah1b</a></li>
   <li>Blah1c</li>
   <li><a href='http://zzzz'>Blah1d</a></li>
  </ul>
 </li>
 <li><a href='http://aaaa'>Blah2</a></li>
 <li>Blah3
  <ul>
   <li><a href='http://xxxx'>Blah2a</a></li>
   <li><a href='http://yyyy'>Blah2b</a></li>
  </ul>
 </li> 
</ul>
And so on... The important thing is that some of their list items are links, some are just text.
I need to select each block of text contained in an <li> that is not already wrapped in an <a> and wrap it in an <a href="#"> so that the above would be transformed into:
<ul>
 <li><a href='#'>Blah1</a>
  <ul>
   <li><a href='http://xxxx'>Blah1a</a></li>
   <li><a href='http://yyyy'>Blah1b</a></li>
   <li><a href='#'>Blah1c</a></li>
   <li><a href='http://zzzz'>Blah1d</a></li>
  </ul>
 </li>
 <li><a href='http://aaaa'>Blah2</a></li>
 <li><a href='#'>Blah3</a>
  <ul>
   <li><a href='http://xxxx'>Blah2a</a></li>
   <li><a href='http://yyyy'>Blah2b</a></li>
  </ul>
 </li> 
</ul>
Shouldn't be that difficult I'm sure, but after an hour of playing I'm getting nowhere.
Try
$('li').contents().filter(function(){
    return this.nodeType == 3 && $.trim($(this).text()).length > 0
}).wrap('<a href="#" />')
Demo: Fiddle
One line of code here:
$("li").not(":has(>a)").wrapInner('<a href="#" />');
jsFiddle
So, if you want to just get the text nodes than, yeah, use .contents(), which will get all nodes, including text nodes.  Here are 2 methods you can use below for this:
$("li").not(":has(>a)").contents().filter(function(){
    return this.nodeType == 3 && $.trim($(this).text()).length > 0
}).wrap('<a href="#" />');
jsFiddle
And here is another approach, just for the sake of something different:
$("li").not(":has(>a)").each(function(){
      var $contents = $(this).contents();
      if ($contents.length)
          $contents.eq(0).wrap('<a href="#" />');
});
jsFiddle
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With