Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selecting list items that are not links

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.

like image 504
PerryW Avatar asked Sep 09 '13 04:09

PerryW


2 Answers

Try

$('li').contents().filter(function(){
    return this.nodeType == 3 && $.trim($(this).text()).length > 0
}).wrap('<a href="#" />')

Demo: Fiddle

like image 134
Arun P Johny Avatar answered Oct 06 '22 00:10

Arun P Johny


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

like image 22
Solomon Closson Avatar answered Oct 06 '22 00:10

Solomon Closson