I recently read an excellent wiki article by Dave Carroll discussing how to create a fancy data driven menu on the force.com platform that was prompted by a rather angry post about not being able to do this on the platform which can be found here.
http://iwritecrappycode.wordpress.com/2009/12/07/visual-force-blows/.
Here's the link to Dave Carroll's wiki tutorial.
The technique in Dave's post is very similar to the one used in OrchestraCMS but if you use OrchestraCMS you don't need to write any apex, visualforce, or create any custom objects. In this post I'm going to show how you can easily create the same sexy data driven menu in OrchestraCMS. All you need to know is html, css, jquery and a bit of OrchestraCMS. In addition the menu will be version controlled.
The first step to create the menu is to install the 30 day free trial of OrchestraCMS and setup a Force.com Sites site. I won't go through the setup of sites or Orchestra, I'll defer to the OrchestraCMS Developer guide which goes through the installation process.Once you have Orchestra installed and setup the next step is to create an OrchestraCMS template. To do this go to setup > develop > pages and click new. The visualforce page editor will open up. Give your template page a name. I called mine MenuTutorial. All OrchestraCMS templates use the same standard skeleton, this tells Orchestra that the visualforce page is one it can use as a template. The source is shown below.
<apex:page id="t" controller="cms.CoreController" standardStylesheets="false" showHeader="false" sidebar="false"> <apex:composition template="{!page_template_reference}">
<apex:define name="header"></apex:define>
<apex:define name="body"></apex:define>
</apex:composition>
</apex:page>
Copy and paste the skeleton into you visualforce page. You can now add standard header html in the header apex:define tag and standard body html in the body apex:define tag. We'll create a very simple template. To define drop zones in the template we use orchestra panel components. There are some specialized panels that limit what can be dropped in a drop zone and more general ones that are more flexible. We'll use a SingleClassStyledMenuPanel to identify where the single menu item with content template ClassStyledMenu can be dropped and we'll use the general Panel component for the body and head. To add the zones simply add the components to the template. The template should now look as shown below.
<apex:page id="t" controller="CMS.CoreController" standardStylesheets="false" showHeader="false" sidebar="false">
<apex:composition template="{!page_template_reference}">
<apex:define name="header">
</apex:define>
<apex:define name="body">
<div class="container">
<div id="jqheader" style="margin:0px; padding:0px;">
<div style="height: 120px; overflow: hidden;">
<CMS:Panel panelName="header" panelController="{!controller}" panelHeight="120px" />
</div>
<div style="height: 35px;">
<CMS:SingleClassStyledMenuPanel panelName="topmenu" panelController="{!controller}" panelHeight="35px" />
</div>
</div>
<div>
<CMS:Panel panelName="column1" panelController="{!controller}" panelHeight="500px" />
</div>
</div>
</apex:define>
</apex:composition>
</apex:page>
The next step is to add the stylesheets, images and javascript. This is the only tricky part since there is currently a minor bug in salesforce that causes an exception to be thrown when trying to access static resources in the local namespace from within an include in a managed package. The solution to this is to create a managed package for your static resources and install that managed package which you can then reference using it's namespace, or if you're in a developer organization you can set a namespace and reference static resources with the namespace you set.
I uploaded a managed package with the static resources so you can install my managed package to speed up the tutorial and avoid creating a new sf developer organization. Here is the link to install the resource package
https://login.salesforce.com/?startURL=%2Fpackaging%2FinstallPackage.apexp%3Fp0%3D04tA0000000Q1o6
There are some minor changes to the stylesheet and javascript found in Dave Carroll's tutorial. Here's what the stylesheet for the OrchestraCMS version looks like:
body {
margin: 0; padding: 0;
font: 10px normal Arial, Helvetica, sans-serif;
background: #ddd url(body_bg.gif) repeat-x;
}
.container {
width: 960px;
margin: 0 auto;
position: relative;
}
#jqheader .menu ul.root-level-list {
list-style: none;
padding: 0;
margin: 0;
float: left;
width: 920px;
background: #222;
font-size: 1.2em;
background: url(topnav_bg.gif) repeat-x;
}
#jqheader .menu ul.root-level-list li.root-level-item {
float: left;
margin: 0;
padding: 0 15px 0 0;
position: relative; /*--Declare X and Y axis base for sub navigation--*/
}
#jqheader .menu ul.root-level-list li.root-level-item a{
padding: 10px 5px;
color: #fff;
display: block;
text-decoration: none;
float: left;
}
#jqheader .menu ul.root-level-list li.root-level-item a:hover{
background: topnav_hover.gif no-repeat center top;
}
#jqheader .menu ul.root-level-list li.root-level-item span { /*--Drop down trigger styles--*/
width: 17px;
height: 35px;
float: left;
background: url(subnav_btn.gif) no-repeat center top;
}
#jqheader .menu ul.root-level-list li.root-level-item span.subhover {background-position: center bottom; cursor: pointer;} /*--Hover effect for trigger--*/
#jqheader .menu ul.root-level-list li.root-level-item ul.level-1-list {
list-style: none;
position: absolute; /*--Important - Keeps subnav from affecting main navigation flow--*/
left: 0; top: 35px;
background: #333;
margin: 0; padding: 0;
display: none;
float: left;
width: 170px;
border: 1px solid #111;
}
#jqheader .menu ul.root-level-list li.root-level-item ul.level-1-list li{
margin: 0; padding: 0;
border-top: 1px solid #252525; /*--Create bevel effect--*/
border-bottom: 1px solid #444; /*--Create bevel effect--*/
clear: both;
width: 170px;
}
#jqheader .menu ul.root-level-list li.root-level-item ul.level-1-list li a {
float: left;
width: 145px;
background: #333 url(dropdown_linkbg.gif) no-repeat 10px center;
padding-left: 20px;
}
#jqheader .menu ul.root-level-list li.root-level-item ul.level-1-list a:hover { /*--Hover effect for subnav links--*/
background: #222 url(dropdown_linkbg.gif) no-repeat 10px center;
}
#jqheader .menu .level-2-list {
display: none;
}
And here is the OrchestraCMS version of the javascript.
$(document).ready(function(){
$("#jqheader .menu .root-level-list .level-1-list").parent().append("<span></span>"); //Only shows drop down trigger when js is enabled (Adds empty span tag after ul.subnav*)
$("#jqheader .menu .root-level-list .root-level-item span").click(function() { //When trigger is clicked...
//Following events are applied to the subnav itself (moving subnav up and down)
$(this).parent().find(".level-1-list").slideDown('fast').show(); //Drop down the subnav on click
$(this).parent().hover(function() {
}, function(){
$(this).parent().find(".level-1-list").slideUp('slow'); //When the mouse hovers out of the subnav, move it back up
});
//Following events are applied to the trigger (Hover events for the trigger)
}).hover(function() {
$(this).addClass("subhover"); //On hover over, add class "subhover"
}, function(){ //On Hover Out
$(this).removeClass("subhover"); //On hover out, remove class "subhover"
});
});
Once you've installed the managed package with the resources add the following two lines to the apex:define head tag
<apex:stylesheet value="{!URLFOR($Resource.mtutorial__jqMenu, 'jqueryMenu.css')}" />
<apex:includeScript value="{!URLFOR($Resource.mtutorial__jqMenu, 'jqueryMenu.js')}" />
The final source for the template page is as shown below.
<apex:page id="t" controller="CMS.CoreController" standardStylesheets="false" showHeader="false" sidebar="false">
<apex:composition template="{!page_template_reference}">
<apex:define name="header">
<apex:stylesheet value="{!URLFOR($Resource.mtutorial__jqMenu, 'jqueryMenu.css')}" />
<apex:includeScript value="{!URLFOR($Resource.mtutorial__jqMenu, 'jqueryMenu.js')}" />
</apex:define>
<apex:define name="body">
<div class="container">
<div id="jqheader" style="margin:0px; padding:0px;">
<div style="height: 120px; overflow: hidden;">
<CMS:Panel panelName="header" panelController="{!controller}" panelHeight="120px" />
</div>
<div style="height: 35px;">
<CMS:SingleClassStyledMenuPanel panelName="topmenu" panelController="{!controller}" panelHeight="35px" />
</div>
</div>
<div>
<CMS:Panel panelName="column1" panelController="{!controller}" panelHeight="500px" />
</div>
</div>
</apex:define>
</apex:composition>
</apex:page>
Click Save and launch OrchestraCMS. Select your site and click Select. Once you're in OrchestraCMS launch the setup tab and click Mange Page Layouts. Click the install link beside the template page you created.
Enter a label and description if you like and click install.
The template is now installed and ready to use. Now lets test it out by creating a page with it. Close the setup tab and create a new page by clicking on Create > Page.
Enter a name for your page and click next.
Select the template you just installed and click next.
Click Finish to launch the page editor. Now lets add the content to our page.
Click Add New Content.
Select Text > Text Block and enter a name. This will be the header text so I called it not surprisingly Header Text. Drag and drop it onto the top most panel.Click the Edit Icon to edit the text.
Enter the header text then select Actions > Save and Close.
Add a class styled menu to the menu panel (the menu panel is the second from the top) and then click the edit icon to edit your menu.
Select sub label position to be Outside Link - Below and leave the menu title blank.Click Add and fill out the necessary details to add Menu items .
If you select an added item (it will highlight with a blue border when selected) and click add, the menu item will be added as a sub menu item to the selected item.You can always reposition items after they've been added by dragging and dropping them. If you drag and drop inwards it will make the item a sub item of the parent.
Once you're done creating your menu click Actions > Save and Close.Now you're ready to preview your menu. Click Actions > Preview.
You could now publish the page to make live on your live site. I've published mine and it can be viewed at the following address.
http://scott.morrisonlive.ca/CMSBETA__Main?name=Menu_Tutorial_TestThere you have it, sexy jquery menus with OrchestraCMS that are version controlled.