views:

275

answers:

0

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 Correct

Sometimes it comes out like this:alt text

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);
    }