Tuesday, June 15, 2010

Layout and Navigation, Part 3

Part 1 of this series showed how to modify the ZF quickstart application to use Zend_Layout for creating a site-wide template. Part 2 added Zend_Navigation for creating a left side menu and breadcrumbs. In this part, we'll have some fun by changing the default menu layout to use a jQuery plugin by Joel Birch called superfish (an enhanced version of suckerfish), a super sexy top navigation menu with dropdowns. Start by folling the preceeding link to the source and downloading the files, then copy the css, images, and js folders into your /public directory. We'll scrap the old style sheet and use the superfish style sheet instead, as well as including and calling the superfish scripts. We will need a very short custom stylesheet as well, which will be in styles.css. Let's go ahead and use the headScript and headLink view helpers as well. The HEAD of layout.phtml should look like this:
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>My Site</title>
<?php
// superfish styles
$this->headLink()
//->appendStylesheet('http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/themes/base/jquery-ui.css')
->appendStylesheet('/css/superfish.css')
->appendStylesheet('/css/styles.css');

// jQuery and superfish scripts (hoverIntent is optional)
$this->headScript()
->appendFile('http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js')
->appendFile('/js/superfish.js')
->appendFile('/js/hoverIntent.js')
->appendScript("$(document).ready(function() { $('ul.sf-menu').superfish(); }");

echo $this->headLink();
echo $this->headScript();
?>
</head>
Superfish is actually very easy to hook up into Zend_Menu because everything keys off the top-level ul class. It turns out that there is a method for setting this, aptly named setUlClass(). So here is the BODY of layout.phtml:
<body>
<?php
// menu helper, use sf-menu as class for top-level ul element
echo $this->navigation()->menu()->setUlClass('sf-menu');
?>

<div class="content">
<?php
// fetch 'content' key using layout helper:
echo $this->layout()->content;
?>
</div>
</body>
Remember how I said we'll need another short stylesheet? That's because otherwise the page content appears to the right of the menu. No problem, just add the following lines to /public/css/styles.css:
div.content {
clear: left;
}
Super easy, no? And this gets us most of the way there. However, if you want those nifty little arrow indicators (and I'm sure you do) we'll have to go one step further and write a custom view helper. Because for any menu items with arrows, superfish wants the html to look like this:
<a href="#" class="sf-with-ul">menu item <span class="sf-sub-indicator"> »</span></a>
We'll create our custom View Helper in /library/My/View/Helper/Superfish.php. Start by specifying the path to your custom view helper in the Bootstrap.php _initNavigation() method, and go ahead and require the file:
//add custom helpers
require_once('My/View/Helper/Superfish.php');
$view->addHelperPath(
APPLICATION_ROOT . '/library/My/View/Helper/Navigation',
'My_View_Helper_'
);
We'll be extending Zend_View_Helper_Navigation_Menu, and the constructor looks like this:
class My_View_Helper_Superfish extends Zend_View_Helper_Navigation_Menu
{
public function superfish(Zend_Navigation_Container $container = null)
{
if (null !== $container) {
$this->setContainer($container);
}
return $this;
}
}
Because all the HTML markup changes are in the link rendering, the function we'll be overwriting is htmlify(). Basically we copy the htmlify function from Menu.php and then add a simple check for subpages, ending up with this:
public function htmlify(Zend_Navigation_Page $page)
{
(code from Menu.php)

// does page have subpages?
if ($page->count()) {
$sub_indicator = '<span class="sf-sub-indicator"> »</span>';
$attribs['class'] .= ' sf-with-ul';
} else {
$sub_indicator = '';
}

return '<' . $element . $this->_htmlAttribs($attribs) . '>'
. $this->view->escape($label)
. $sub_indicator
. '';
}
All you need to do to now use your superfish view helper is to call it in the layout.phtml instead of menu, like this:
echo $this->navigation()->superfish()->setUlClass('sf-menu');
Have fun playing around with the menus, adding new items, and reorganizing them to contain multiple levels, but as far as integrating superfish and Zend Framework is concerned, we're done. Happy coding!

No comments:

Post a Comment