Software Development Technologies and Solutions
SharePoint | .NET | MCMS | MS SQL | Office

If you are a SharePoint developer, then you will be in need to customize the default SharePoint menu control.  This new feature in MOSS 2007 is great and it allows for suitable level of customization, but unfortunately, this level is not enough for such portal which I’m involved in these days.

I’ve decided to customize the default menu instead of developing new control. To realize the problem suppose that you want your menu to have the following structure:

Site1   Site2  Site3  Site4 …..

   Site1Child1 . Site1Child2 . Site1Child3…

As you see, every static item has its own style, also it should has its own hover style, and dynamic items should appear horizontally in case of mouse over the static item.
If you edited your master page by sharepoint designer, you will notice that the default SharePoint menu allows you to define only one class for all static items, so we need to edit the static menu template, but even though, the template allows you only for editing "link"s' inner HTML, however you can add another link inside this template, it is a good idea for applying deferent classes:

 

<StaticItemTemplate>
    <div id=
"Static" runat="Server" class='<%# GetStaticClass()%>' onmouseover='<%# GetShowFunction()%>' onmouseout='<%# GetHideFunction()%>'>
        <asp:hyperLink runat=
"Server" id="urlNavS"  NavigateUrl='<%# Eval("DataPath")%>' Text='<%# Eval("Text")%>' />
    </div>
    <div id='<%# GetDynamicID()%>' class='dynPanel'  onmouseover='<%# GetShowFunction()%>' onmouseout='<%# GetHideFunction()%>'></div>
 </StaticItemTemplate>

 

You will notice that I’ve put all classes and javascript functions to be driven from C# script, but first you should be permitted from SharePoint to execute C# script in SharePoint pages. To do that you need first to add the following section under <SafeMode> tag in web.config:

 

<PageParserPaths>
   <PageParserPath VirtualPath=
"/_catalogs/masterpage/*" CompilationMode="Always" AllowServerSideScript="true" />
</PageParserPaths>

 

I’ve written C# script for providing class name for each item and JavaScript functions.
That will solve the first problem, but further more we need to display dynamic items horizontally, I think this hard to be done by the default dynamic template, so I’ve assigned a class to hide the default dynamic items and I’ve began to generate them by C# code using OnDataBound event.
Here is the full code:


<div id="MenuDiv">
     <SharePoint:AspMenu ID=
"GlobalNav" Runat="server" DataSourceID="SiteMapDataSource1" Orientation="Horizontal" StaticDisplayLevels="1" MaximumDynamicDisplayLevels="1" StaticSubMenuIndent="2" DynamicHorizontalOffset="0" DynamicVerticalOffset="4" StaticEnableDefaultPopOutImage="false" ItemWrap="false" Width="0%" OnDataBound="MenuDataBound">
                 
          <StaticMenuItemStyle CssClass=
"" ItemSpacing="4px" />
          <StaticSelectedStyle CssClass=
"" ItemSpacing="4px" />
          <DynamicMenuItemStyle CssClass=
"dynamicItems" />
             <StaticItemTemplate>
                  <div id=
"Static" runat="Server" class='<%# GetStaticClass()%>' onmouseover='<%# GetShowFunction()%>' onmouseout='<%# GetHideFunction()%>'>
                       <asp:hyperLink runat=
"Server" id="urlNavS"  NavigateUrl='<%# Eval("DataPath")%>' Text='<%# Eval("Text")%>' />
                  </div>
                  <div id='<%# GetDynamicID()%>' class='dynPanel'  onmouseover='<%# GetShowFunction()%>' onmouseout='<%# GetHideFunction()%>'></div>
              </StaticItemTemplate>
             <StaticHoverStyle CssClass=
"topNavHover"/>
            </SharePoint:AspMenu>
            <PublishingNavigation:PortalSiteMapDataSource ID=
"siteMapDataSource1" Runat="server" SiteMapProvider="CombinedNavSiteMapProvider" EnableViewState="true" StartFromCurrentNode="true" StartingNodeOffset="0" ShowStartingNode="false" TreatStartingNodeAsCurrent="true" TrimNonCurrentTypes="Heading"/>
            <div id=
"dynamicItems" runat="server"></div>


           
<script runat="server">
            int stCount
= 0;
           
            protected string GetStaticClass
()
            {
                  stCount
+= 1;
                  return "staticItem"
+ stCount .ToString() ;                            
            }
           
            protected string GetDynamicID
()
            {
                  return "DynamicItem"
+ stCount .ToString() ;                           
            }
       
           
            protected string GetShowFunction
()
            {
                  return "showDynamicItems("
+ stCount .ToString() + ")" ;                           
            }
           
            protected string GetHideFunction
()
            {
                  return "hideDynamicItems("
+ stCount .ToString() + ")" ;                           
            }
       
            protected void MenuDataBound
(object sender, EventArgs e)
            {
                  int ItemIndex
= 0;
                  int subIndex
= 0;
                  string divContent
= "";
                 
                  foreach
(System.Web.UI.WebControls.MenuItem item in GlobalNav.Items)
                  {
                        subIndex
= 0;
                        foreach
(System.Web.UI.WebControls.MenuItem cItem in item.ChildItems )
                        {
                              if
(subIndex == 0)
                              {
                                    divContent
+= "<div style='display:none' id='subItems" + ItemIndex.ToString() + "'><table class='MenuSubDiv" + (ItemIndex + 1).ToString() + "' ><tr>";
                              }
                              divContent
+= "<td><a href='" + cItem.DataPath + "'>" + cItem.Text + "</a></td>";
                              if
(subIndex == item.ChildItems.Count-1)
                              {
                                    divContent
+= "</tr></table></div>";
                              }
                              else
                              {
                                    divContent
+= "<td>&nbsp;<img src='/_layouts/images/menu_sub_bullet.gif'/>&nbsp;</td>";
                              }
                              subIndex
+= 1;
                        }
                        ItemIndex
+= 1;
                  }
                  dynamicItems
.InnerHtml += divContent ;                                 
            }
           
       
</script>
       
<script language="javascript" type="text/javascript">
       
            function showDynamicItems
(num)
            {
                  try
                  {
                        var dv
= document.getElementById("subItems" + (num -1).toString());
                        var dynCont
= document.getElementById("DynamicItem" + num.toString());
                                   
                        if
(dynCont.style.display!="block")
                        {
                              hideAll
();
                              dynCont
.innerHTML = dv.innerHTML ;
                              dynCont
.style.display = "block" ;
                        }
                  }
                  catch
(e)
                  {
                  }
            }
           
            function hideAll
()
            {
                  var count
=1;
                  while
(true)
                  {
                        try
                        {
                              var dynCont
= document.getElementById("DynamicItem" + count.toString());
                              if
(dynCont.style.display != "none")
                              {
                                    dynCont
.style.display = "none" ;
                              }
                              count
+= 1;
                        }
                        catch
(e)
                        {
                              return;
                        }
                  }
            }
           
            function hideDynamicItems
(num)
            {
                  try
                  {
                        var dynCont
= document.getElementById("DynamicItem" + num.toString());
                        dynCont
.style.display = "none" ;
                  }
                  catch
(e)
                  {
                  }
            }
       
       
</script>
   </div>
  

 
[Update April, 11, 2009]
I'm so sorry for being so busy last year, I'm including the CSS file here for all people whom requested it.
Trackbacks :
http://devexpert.net/blog/pt/blog/track.aspx?id=17
Hi Mahdi,

We're trying to create the same nav layout as your example.... but we can't get your code to work.

Are we missing something?

Thanks.
Comment By JONESY At 6/22/2007 5:25 AM
Dear Jonesy

Just let me to know what is happening, do you get an error or the code is doing nothing, for your information; I did not include CSS files in this article, I've just presented the idea to include C# script. if you need this css files I can send it to you.
Comment By Mahdi Abdulhamid At 6/22/2007 5:52 AM
Hi Mahdi,

That would be great.

Cheers
Comment By JONESY At 6/22/2007 6:35 AM
The CSS file has been sent.

good luck
Comment By Mahdi Abdulhamid At 6/22/2007 6:52 AM
Hi

I think this is great.

I need to do something similar on mysites.

Specifically I need to replace the words 'My Home' and 'My Profile' with 'Home' and 'Profile'

I added the code to allow me to execute C# script but I still get the error.

Any ideas? Or even a better solution to removing the word 'My' from everything?

Thanks!
Comment By MMDG At 7/31/2007 1:08 PM
Dear MMDG
I hope everything is ok with you, be sure of including the right path in 'VirtualPath=', also if you have extended your web application to another header name, then you will get two web.config, you will need to configure both of them. but i'm wondering about the code you've written to change that link text, if it is possible, let me have a look on it.

good luck
Comment By Mahdi Abdulhamid At 7/31/2007 4:27 PM
Hi

Thank you for the response.

I actually haven't even gotten to the point of changing the link text. I was hoping to see what Eval('Text').ToString() would bring me.

But I still keep getting the web.config error.
The 'VirtualPath=' is correct and I made the same change in both config files.

Any advice?

Thanks again
Comment By MMDG At 8/6/2007 12:35 PM
Great article! Is it possible to send me the CSS files? Thanks.
Comment By Joseph Sanders At 9/7/2007 6:51 AM
Hi.

Great article. I would try your example. Could you send me the CSS.

Thanks.
Comment By Gabriele At 9/28/2007 8:34 AM
Comments :
Name :
Email :
URL :
       
Comments :
Allowed Tags : <A>, <B>, <I>, <BLOCKQUOTE>