Style the last link in an autonav?

Permalink 1 user found helpful
Hi all

It's easy enough to style the first link in an autonav by defining the 'first' CSS class, but what about the last link?

I've got some borders between my horizontal menu items, but I don't want them on the left of the first item or the right of the last item. I managed it fine with the first item but I can't see a way in the header_menu autonav template to apply a class to the last menu item.

Any help would be much appreciated! :)

melat0nin
 
jordanlev replied on at Permalink Reply
jordanlev
Try this:
Copy the "header_menu.php" file from this directory:
YOURSITE/concrete/blocks/autonav/templates/
to a new directory that you create here:
YOURSITE/blocks/autonav/templates/

Then edit that file. Find this line:
$isFirst = true;

and add these new lines below that one (but above the "foreach" line):
$count = count($aBlocks);
$i = 1;

Then, find this line:
echo '<li class="'.$navSelected.' '.$isFirstClass.'">';

and directly ABOVE it (but under the "else $isFirstClass..." line), add this:
$isFirstClass .= ($i++ == $count) ? ' last' : '';

Now when you place the autonav block on a page, click it and choose "Custom Template", and then choose the "Header Menu" from the list. In your stylesheet, you can identify this last item like so:
ul.nav-header li.last { ... }

-Jordan
melat0nin replied on at Permalink Best Answer Reply
melat0nin
Thanks for your suggestion.

It didn't quite work for me, but I tweaked the code to get this, which does work:

<?php 
   defined('C5_EXECUTE') or die(_("Access Denied."));
   $aBlocks = $controller->generateNav();
   $c = Page::getCurrentPage();
   echo("<ul class=\"nav-header\">");
   $nh = Loader::helper('navigation');
   $isFirst = true;
   $count = count($aBlocks);
   $i = 1;
   foreach($aBlocks as $ni) {
      $_c = $ni->getCollectionObject();
      if (!$_c->getCollectionAttributeValue('exclude_nav')) {
         if ($ni->isActive($c) || strpos($c->getCollectionPath(), $_c->getCollectionPath()) === 0) {
            $navSelected='nav-selected';
         } else {


:)
accountnotinuse replied on at Permalink Reply
Thought I would post for reference and people who come across this via search.

The above solution doesn't quite work.

$count = count($aBlocks);

Counts all pages, including those that are excluded from the navigation. So if you have 4 pages and 3 excluded pages the count will be 7. This means the last page will not be detected correctly and the class won't be applied as desired.

To get around this you need to subtract the exlcuded pages from your count as follows:

foreach($aBlocks as $ni) 
      {
         $_c = $ni->getCollectionObject();
         if ($_c->getCollectionAttributeValue('exclude_nav')) 
         {
            $count--;
         }
      }
dancer replied on at Permalink Reply
dancer
Hello,
This is exactly what I am looking for but it would seem that there is still a slight bug.

The script is placing the "last" class on the last but one.

I think this may have something to do with my "Home" link being in the autonav.

Is there a way to take this into consideration?

Thanks so much in advance :)

D!!

p.s I have zero PHP knowledge


<?php 
   defined('C5_EXECUTE') or die(_("Access Denied."));
   $aBlocks = $controller->generateNav();
   $c = Page::getCurrentPage();
   echo("<ul class=\"nav-header\">");
   $nh = Loader::helper('navigation');
   $isFirst = true;
   $count = count($aBlocks);
   $i = 1;
   foreach($aBlocks as $ni) 
      {
         $_c = $ni->getCollectionObject();
         if ($_c->getCollectionAttributeValue('exclude_nav')) 
         {
            $count--;
beebs93 replied on at Permalink Reply
beebs93
Try this (as requested by Biscutty on the forums):

<?php 
  defined('C5_EXECUTE') or die("Access Denied.");
  $aBlocks = $controller->generateNav();
  $c = Page::getCurrentPage();
  echo("<ul class=\"nav-header\">");
  $nh = Loader::helper('navigation');
  // Filter out any excluded pages
  $aBlocks = array_filter($aBlocks,
    create_function('$v', '
      $c = $v->getCollectionObject();
      return !$c->getAttribute("exclude_nav") ? TRUE : FALSE;
    ')
  );
  // Determine last element key
  end($aBlocks);


Basically, you filter out any excluded pages first, then you'll have an array with no fear of skipping elements thus you can use the current iteration's key to check against the last key of the array.
adamjohnson replied on at Permalink Reply
adamjohnson
Silly PHP devs, this can be done with CSS 2.1:

#myelement a:last-child { your stuff goes here }


Just put :last-child on whatever you want to style and you'll be good. ;-)
beebs93 replied on at Permalink Reply
beebs93
True, but while :first-child has wide support among legacy browsers, :last-child does not thus the need to programatically tag the last child element.
adamjohnson replied on at Permalink Reply
adamjohnson
Very true. Sometimes you gotta' accommodate for IE. I usually use :last-child in combination with IE9.js in a conditional comment to get everything tip top:

http://code.google.com/p/ie7-js/...
jordanlev replied on at Permalink Reply
jordanlev
Wow, I never saw that script before -- looks really handy. How does it compare to other similar things (in your experience)? I've used CSSPIE before to limited effect, but I think that's more for getting things like rounded corners and drop-shadows to work in IE, whereas this seems to be more for smoothing out differences in CSS?
adamjohnson replied on at Permalink Reply
adamjohnson
Yeah, IE9.js does different things in comparison to CSS3Pie. The demo page has a full list of what it adds support for:

http://ie7-js.googlecode.com/svn/test/index.html...

The IE9 flavor includes support for HTML5 elements. I'm making almost exclusively HTML5 sites these days; therefor, I figure it's better to include IE9.js as one file versus an HTML5 shim and whatever else (Selectivizr, CSS3Pie, [your IE shim here]). Overall, I've been very pleased with it and have found it to be a good solution in solving CSS differences.
beebs93 replied on at Permalink Reply
beebs93
A JS shimmy can help fix it, but it can be turned off. While the earth probably won't implode if a :last-child element isn't parsed properly, using JS to accommodate IE7 bugs that can easily be addressed in server-side languages can a be a bit overkill.

(Or, try to make the first child the exception and treat the rest with the general styling)
jordanlev replied on at Permalink Reply
jordanlev
Silly non-real-world designers, using CSS that doesn't work for FORTY PERCENT of people's browsers!
(last-child selector is not supported by IE6-8)

All in good fun, btw -- much respect to Adam (riotaj), he does really great things for the community here!
adamjohnson replied on at Permalink Reply
adamjohnson
Haha! So good.
c5mix replied on at Permalink Reply
You can do this with just css. All you need to do is add a border-left to the list items and then use the first-child selector to not show it on the first item in nav like this:
ul li {
border-left:1px solid #000;
}
ul li:first-child {
border-left:none;
}
verb replied on at Permalink Reply
I like this solution - pure CSS, fast with no overrides to the core. Thanks c5mix!
mnakalay replied on at Permalink Reply
mnakalay
Hi,
I know it's a bit of an old thread by now but in autonav, the first li has a class of first by default as appears in the code quoted here.
so probably this would work:
ul li {
border-left:1px solid #000;
}
ul li.first {
border-left:none;
}

which is exactly the same as c5mix solution above but using the class name instead of the first-child selector.

I know, I know, stating the obvious :)