I have a database driven menu Helper that gets called from within my master page:
<div class="topBar">
<%= Html.MenuTree(39, false, "first", "last") %>
<div class="clear"></div>
</div>
Below is the code that outputs my HTML unordered list. The problem is that sometimes the output of the menu is completely wrong and all over the place ie. sub menu items appear as equal as top menu items.
I cannot find any pattern to why it does it so thought I'd post the code to see if anyone can spot the problem. My only other thought is that somehow its half cached half called and mixes the output.
This is what it should look like
Sometimes it comes out like this:
Here's the code (the boolean IsAdmin is false in this scenario):
public static string MenuTree(this HtmlHelper helper, int MenuCategoryID, bool Admin, string firstCssClass, string lastCssClass)
{
//TODO: Check for Subsonic fix for UNION bug
IOrderedQueryable<Menu> menuItems;
if (Admin)
{
menuItems = (from menu2 in Menu.All()
join pages in WebPage.All() on menu2.PageID equals pages.ID
join pagesRoles in PageRole.All() on pages.ID equals pagesRoles.PageID
join roles in aspnet_Role.All() on pagesRoles.RoleId equals roles.RoleId
where Roles.GetRolesForUser().Contains(roles.RoleName) && menu2.CategoryID == MenuCategoryID && menu2.Visible
select menu2).Distinct().OrderBy(f => f.OrderID);
}
else
{
menuItems = (from menu2 in Menu.All()
join pages in WebPage.All() on menu2.PageID equals pages.ID
where menu2.CategoryID == MenuCategoryID && menu2.Visible
select menu2).Distinct().OrderBy(f => f.OrderID);
}
var nonlinkedmenuItems = (from menu in Menu.All().Where(x => x.PageID == null && x.CategoryID == MenuCategoryID && x.Visible).OrderBy(f => f.OrderID) select menu);
var allCategories = menuItems.ToList().Concat<Menu>(nonlinkedmenuItems.ToList()).OrderBy(p => p.OrderID).ToList();
allCategories.ForEach(x => x.Children = allCategories.Where(y => y.ParentID == x.ID).OrderBy(f => f.OrderID));
Menu home = null;
if (Admin)
{
home = (from menu in Menu.All()
join pages in WebPage.All() on menu.PageID equals pages.ID
where pages.MenuName == "Home" && pages.IsAdmin
select menu).SingleOrDefault();
}
IEnumerable<Menu> topLevelItems;
if (Admin)
topLevelItems = allCategories.Where(f => f.ParentID == 0 && (f.Children.Count() > 0 || f.ID == home.ID));
else
topLevelItems = allCategories.Where(f => f.ParentID == 0);
var topLevelItemList = topLevelItems.ToList();
sbMenu.Length = 0;
sbMenu.AppendLine("<ul>");
LoopChildren(helper, Admin, topLevelItemList, 0, firstCssClass, lastCssClass);
sbMenu.AppendLine("</ul>");
string menuString = sbMenu.ToString();
//if ((menuString.IndexOf("<li>")) > 0)
// menuString = menuString.Insert((menuString.IndexOf("<li>") + 3), " class='first'");
//if (menuString.LastIndexOf("<li>\r\n") > 0)
// menuString = menuString.Insert((menuString.LastIndexOf("<li>\r\n") + 3), " class='last'");
return sbMenu.ToString();
}
private static void LoopChildren(this HtmlHelper helper, bool Admin, List<Menu> CurrentNode, int TabIndents, string firstCssClass, string lastCssClass)
{
for (int i = 0; i < CurrentNode.Count; i++)
{
sbMenu.Append(Tabs(TabIndents + 1));
string linkUrl = "";
string urlTitle = "";
if (CurrentNode[i].PageID != null)
{
WebPage item = WebPage.SingleOrDefault(x => x.ID == CurrentNode[i].PageID);
linkUrl = item.URL;
urlTitle = item.MenuName;
}
else
{
linkUrl = CurrentNode[i].URL;
urlTitle = CurrentNode[i].Title;
}
//Specify a RouteLink so that when in Error 404 page for example the links don't become /error/homepage
//If in admin we can manually write the <a> tag as it has the controller and action in it
bool selected = false;
if (helper.ViewContext.RouteData.Values["pageName"] != null && helper.ViewContext.RouteData.Values["pageName"].ToString() == linkUrl)
selected = true;
string anchorTag = Admin ? "<a href='" + linkUrl + "'>" + urlTitle + "</a>" : helper.RouteLink(urlTitle, new { controller = "WebPage", action = "Details", pageName = linkUrl });
if (TabIndents == 0 && i == 0 && firstCssClass != null)
sbMenu.AppendLine("<li class='" + firstCssClass + "'>" + anchorTag);
else if (TabIndents == 0 && i == (CurrentNode.Count - 1) && lastCssClass != null)
sbMenu.AppendLine("<li class='" + lastCssClass + "'>" + anchorTag);
else if (selected)
sbMenu.AppendLine("<li class='selected'>" + anchorTag);
else
sbMenu.AppendLine("<li>" + anchorTag);
if (CurrentNode[i].Children != null && CurrentNode[i].Children.Count() > 0)
{
sbMenu.Append(Tabs(TabIndents + 2));
sbMenu.AppendLine("<ul>");
LoopChildren(helper, Admin, CurrentNode[i].Children.ToList(), TabIndents + 2, "", "");
sbMenu.Append(Tabs(TabIndents + 2));
sbMenu.AppendLine("</ul>");
}
sbMenu.Append(Tabs(TabIndents + 1));
sbMenu.AppendLine("</li>");
}
}
private static string Tabs(int n)
{
return new String('\t', n);
}