Accordion as a sitemap

Last post 05-06-2008 9:56 AM by whatispunk. 18 replies.

Sort Posts:

  • Accordion as a sitemap

    03-27-2007, 8:07 PM
    • Loading...
    • whatispunk
    • Joined on 03-06-2007, 10:21 PM
    • Winnipeg
    • Posts 721

    I've been trying all day to get this to work and I am fed up. I just can't get it to render correctly. For whatever reason my code is cramming everything into one pane. Someone please take a look at my code and point me in the right direction.

     

        Protected Sub AccordionSiteMap_Load(ByVal sender As Object, ByVal e As EventArgs)
            Dim p As New AjaxControlToolkit.AccordionPane

            If SiteMap.RootNode.HasChildNodes Then
                Dim RootNodesEnumerator As IEnumerator = SiteMap.RootNode.ChildNodes.GetEnumerator()
                Dim nodeTxt As String = ""
                Dim accCtrl As New LiteralControl
                Dim HeaderClass As String = "AccordionHeader"
                Dim ContentClass As String = "AccordionContent"
                Dim paneCounter As Integer = 0
                While RootNodesEnumerator.MoveNext

                    p.ID = "Pane" & Regex.Replace(RootNodesEnumerator.Current.ToString(), "\s+", "")

                    With p.HeaderContainer.Controls
                        .Add(New LiteralControl("<div class='"))
                        .Add(New LiteralControl(HeaderClass))
                        .Add(New LiteralControl("'><a href=''>"))
                        .Add(New LiteralControl(RootNodesEnumerator.Current.title))
                        .Add(New LiteralControl("</a></div>"))
                    End With

                    If RootNodesEnumerator.Current.HasChildNodes Then
                        Dim ChildNodesEnumerator As IEnumerator = RootNodesEnumerator.Current.ChildNodes.GetEnumerator()
                        With p.ContentContainer.Controls
                            .Add(New LiteralControl("<div class='"))
                            .Add(New LiteralControl(ContentClass))
                            .Add(New LiteralControl("'>"))
                            While ChildNodesEnumerator.MoveNext
                                .Add(New LiteralControl("<a href='"))
                                .Add(New LiteralControl(ChildNodesEnumerator.Current.url))
                                .Add(New LiteralControl("'>"))
                                .Add(New LiteralControl(ChildNodesEnumerator.Current.title))
                                .Add(New LiteralControl("</a><br />"))
                            End While
                            .Add(New LiteralControl("</div>"))
                        End With
                    End If
                    AccordionSiteMap.Panes.Add(p)

                End While

            End If

    Remember: mark posts that helped you as the answer to aid future readers

    Why UpdatePanels Are Dangerous
    Why You Should Not Place Your Whole Site In An UpdatePanel
  • Re: Accordion as a sitemap

    03-28-2007, 9:04 AM
    Answer
    • Loading...
    • whatispunk
    • Joined on 03-06-2007, 10:21 PM
    • Winnipeg
    • Posts 721

    Well anyone who is familiar with VB.Net should spot my mistake pretty quickly. However, it has been a while since I've done any coding. Let alone with VB. I am more of a C guy. Which begs the question, why don't I use C#? Well, I'm lazy and case sensitivity and all that type casting seems like to much of a pain the ass.

     
    But alas, after a good night's rest, I remember a little thing about the behavior of objects and realized my problem lay in the p object. So I added the following lines at the beginning of my first While loop:

                    p = Nothing
                    p = New AjaxControlToolkit.AccordionPane

     

    And low and behold it works now! But if anyone can spot a better way, please let me know. 


     

    Remember: mark posts that helped you as the answer to aid future readers

    Why UpdatePanels Are Dangerous
    Why You Should Not Place Your Whole Site In An UpdatePanel
  • Re: Accordion as a sitemap

    03-28-2007, 5:33 PM
    • Loading...
    • whatispunk
    • Joined on 03-06-2007, 10:21 PM
    • Winnipeg
    • Posts 721

    Just in case in the future someone is looking to make the Accordion control into a sitemap also I am going to post my final code. Well, it's probably not completely final, but its working beatifully and it looks freakin awesome! Sorry for the lack of comments in the code.

    The AccordianSiteMap_Load() is called during the Page_Load event and parses the SiteMap collection to fill the Accordion panes.

    The AccordionSiteMap_OpenCurrentPane(), also called from Page_Load, opens the current pages pane in the Accordian control when the current page changes. It does this with the help of RootIndexofCurrentNode() which searches through the SiteMap collection to determine which pane the current page belongs to. A warning about this function though, if your SiteMap tree is very deep this function might slow your page load times down. It is a recursive function so depending on the depth of your sitemap the times will vary. My SiteMap is only 3 levels deep and the time isn't even noticeable.

    Also, I'd like to say, I haven't done any programming in quite a long time (3 years) and I am quite proud of myself for remembering how to code recursion (compiled and ran properly on first try), but if anyone has any suggestions or spots a mistake anywhere in my code please let me know!

    ' HTML

    <cc1:Accordion ID="AccordionSiteMap" runat="server" AutoSize="none" 
     FramesPerSecond="24" RequireOpenedPane="false" SuppressHeaderPostbacks="true"
     TransitionDuration="500" HeaderCssClass="AccordionHeader" ContentCssClass="AccordionContent"> 
    </cc1:Accordion>
     

    ' VB CODE

        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            AccordionSiteMap_Load(sender, e)
            AccordionSiteMap_OpenCurrentPane(sender, e)
        End Sub
    
        Protected Sub AccordionSiteMap_Load(ByVal sender As Object, ByVal e As EventArgs)
            Dim p As New AjaxControlToolkit.AccordionPane
            Dim linkClass, currentLinkClass, nonCurrentLinkClass As String
            linkClass = ""
            currentLinkClass = "AccordionCurrentLink"
            nonCurrentLinkClass = "AccordionLink"
    
            If SiteMap.RootNode.HasChildNodes Then
                Dim RootNodesEnumerator As IEnumerator = SiteMap.RootNode.ChildNodes.GetEnumerator()
                Dim paneCounter As Integer = 0
                While RootNodesEnumerator.MoveNext
                    p = Nothing
                    p = New AjaxControlToolkit.AccordionPane
                    p.ID = "Pane" & Regex.Replace(RootNodesEnumerator.Current.ToString(), "\s+", "")
                    p.HeaderContainer.Controls.Add(New LiteralControl("<span>" & RootNodesEnumerator.Current.Title & "</span>"))
                    If RootNodesEnumerator.Current.HasChildNodes Then
                        Dim ChildNodesEnumerator As IEnumerator = RootNodesEnumerator.Current.ChildNodes.GetEnumerator()
                        While ChildNodesEnumerator.MoveNext
                            If SiteMap.CurrentNode Is Nothing Then
                                linkClass = nonCurrentLinkClass
                            ElseIf SiteMap.CurrentNode.ToString = ChildNodesEnumerator.Current.ToString Then
                                linkClass = currentLinkClass
                            Else
                                linkClass = nonCurrentLinkClass
                            End If
                            p.ContentContainer.Controls.Add(New LiteralControl("<a class='" & linkClass & "' "))
                            p.ContentContainer.Controls.Add(New LiteralControl("href='" & ChildNodesEnumerator.Current.url & "'>"))
                            p.ContentContainer.Controls.Add(New LiteralControl(ChildNodesEnumerator.Current.title & "</a>"))
                        End While
                    End If
    
                    AccordionSiteMap.Panes.Add(p)
    
                End While
            End If
        End Sub
    
        Protected Sub AccordionSiteMap_OpenCurrentPane(ByVal sender As Object, ByVal e As EventArgs)
            If SiteMap.CurrentNode Is Nothing Then
                AccordionSiteMap.SelectedIndex = -1
            Else
                AccordionSiteMap.SelectedIndex = RootIndexofCurrentNode(SiteMap.RootNode.ChildNodes)
            End If
        End Sub
    
        Private Function RootIndexofCurrentNode(ByVal Nodes As SiteMapNodeCollection) As Short
            Dim index As Short = -2
            If Nodes Is Nothing Then
                RootIndexofCurrentNode = -1
            ElseIf Nodes.Contains(SiteMap.CurrentNode) Then
                RootIndexofCurrentNode = Nodes.IndexOf(SiteMap.CurrentNode)
            Else
                For Each n As SiteMapNode In Nodes
                    index = RootIndexofCurrentNode(n.ChildNodes)
                    If index <> -1 Then
                        If n.ParentNode.ToString = SiteMap.RootNode.ToString Then
                            Return SiteMap.RootNode.ChildNodes.IndexOf(n)
                        Else
                            Return index
                        End If
                    End If
                Next
                Return -1
            End If
    
     

    'CSS

    div[id*="AccordionSiteMap"] {font-family: Times;
     text-align: center;
     width: 200px;
     margin: 0;
     padding: 0;
     overflow: hidden !important;
    }
    
    .AccordionHeader + div {
     position: relative;
     z-index: 1;
     top: -5px;
    }
    
    .AccordionHeader {
     background: url(Images/AccordionHeader.png) no-repeat;
     height: 30px;
     position: relative;
     z-index: 10;
     margin-top: 5px;
    }
    
    .AccordionHeader span {
     display: block;
     color: #DDDDDD;
     font-weight: bold;
     text-decoration: none;
     font-variant: small-caps;
     line-height: 30px;
     letter-spacing: .2em;
    }
    
    .AccordionHeader span:hover {
     color: white;
     font-weight: 500;
     cursor: pointer;
    }
    
    .AccordionContent {
     width: 180px;
     margin: 0 auto;
     border-bottom: 2px solid black;border-right: 2px solid black;
    }
    
    .AccordionContent > a {
     display: block;
     white-space: nowrap;
     border-top: 1px solid black;
     padding: 1px 0;
     background: url(Images/AccordionContent.png) repeat-y;
    }
    
    .AccordionContent > a:first-child {
     border-top: none !important;
     height: 22px;
     line-height: 22px;
    }
    .AccordionContent > a:hover {
     background: url(Images/AccordionContentOver.png) repeat-y;
     color: White;
    }
    
    .AccordionLink {
     color: Black; 
    }
    
    .AccordionCurrentLink {
     color: Maroon;
    }
    
     
     
    Here's a screenshot of what it looks like. I don't have the site online yet so this is the best I can do. And ignore the dumb content in the main window.
    SCREENSHOT1
    Remember: mark posts that helped you as the answer to aid future readers

    Why UpdatePanels Are Dangerous
    Why You Should Not Place Your Whole Site In An UpdatePanel
  • Re: Accordion as a sitemap

    09-22-2007, 12:17 PM
    Answer
    • Loading...
    • Stoutheart
    • Joined on 07-11-2007, 12:39 PM
    • Delphos, OH
    • Posts 16

    For those of you who want to know how to do this in C# here is what I used.  Granted the menu is fairly simple, but it works like a charm and seems like a bit less coding.

    Aspx page

            <asp:ScriptManager ID="ScriptManager1" runat="server" />
            <div>
                <h4>Dynamic Accordion Menu</h4>
                 <cc1:Accordion ID="myAccordion" runat="server" SuppressHeaderPostbacks="true" >
                </cc1:Accordion>
            </div>

    CodeFile:

        protected void Page_Load(object sender, EventArgs e)
        {
            for (int i = 0; i < SiteMap.RootNode.ChildNodes.Count; i++)
            {
                //GRABS SITEMAP MAIN ITEMS (UNDER HOME)
                SiteMapNode smn = (SiteMapNode)SiteMap.RootNode.ChildNodes[i];
    
                //CREATES ACCORDION PANE
                AjaxControlToolkit.AccordionPane p = new AjaxControlToolkit.AccordionPane();
    
                //CREATE UNIQUE PANE ID
                p.ID = "Pane" + i;
    
                //CREATE HEADER ITEM
                HyperLink hlHeader = new HyperLink();
                hlHeader.NavigateUrl = SiteMap.RootNode.ChildNodes[i].Url.ToString();
                hlHeader.Text = SiteMap.RootNode.ChildNodes[i].Title.ToString();
    
                //ADDS HEADER LINK TO PANE (HEADER)
                p.HeaderContainer.Controls.Add(hlHeader);
    
                //CHECKS IF HEADER ITEM HAS CHILDREN
                    if (smn.HasChildNodes)
                    {
                        //CREATE BULLETED LIST OF CHILDREN
                        BulletedList blMenu = new BulletedList();
                        blMenu.DisplayMode = BulletedListDisplayMode.HyperLink;
    
                        //CREATES LIST ITEMS WITHIN BULLETED LIST FOR CHILDREN
                        for (int j = 0; j < smn.ChildNodes.Count; j++)
                        {
                            blMenu.Items.Insert(0, (new ListItem(smn.ChildNodes[j].Title.ToString(), smn.ChildNodes[j].Url.ToString())));
                        }
                        //ADDS BULLETED LIST TO PANE (CONTAINER)
                        p.ContentContainer.Controls.Add(blMenu);
                    }
                //ADDS PANE TO ACCORDION
                myAccordion.Panes.Add(p);
            }
        }
    **************
    * Stoutheart *
    **************
  • Re: Accordion as a sitemap

    11-26-2007, 10:34 PM
    • Loading...
    • whatispunk
    • Joined on 03-06-2007, 10:21 PM
    • Winnipeg
    • Posts 721

    Ya ya. It is a little bit less coding :P But the extra functions in my code will make sure the pane containing the current page will be open after the page is loaded.

    I've converted all my code to C# now too. Man am I glad to be done with VB (fingers crossed).

    I'll probably post it a little later after I see if I can make some optimizations based on your version.

    Thanks.

    Remember: mark posts that helped you as the answer to aid future readers

    Why UpdatePanels Are Dangerous
    Why You Should Not Place Your Whole Site In An UpdatePanel
  • Re: Accordion as a sitemap

    11-27-2007, 8:03 AM
    • Loading...
    • Stoutheart
    • Joined on 07-11-2007, 12:39 PM
    • Delphos, OH
    • Posts 16

    Big Smile I now have a version that will make sure the appropriate pane is open when the page is loaded.  I had to make some tweaks to get my code to work with a dynamic sitemap pulled from an SQL database, but it's working now.  Sometime I'll post my code again as well. Big Smile

    **************
    * Stoutheart *
    **************
  • Re: Accordion as a sitemap

    11-27-2007, 10:53 AM
    • Loading...
    • TCavins
    • Joined on 05-23-2007, 2:06 PM
    • Detroit, MI
    • Posts 138

    Does this handle multiple levels?

     For instance, in the screenshot posted, lets say the Elevator section had more sections underneath it. Would they also expand in another accordion control?

     

    Tim

  • Re: Accordion as a sitemap

    11-27-2007, 11:43 AM
    • Loading...
    • Stoutheart
    • Joined on 07-11-2007, 12:39 PM
    • Delphos, OH
    • Posts 16

    As far as my example goes, no it does not support more than 1 level under it as an accordion control.  You can still have a menu control load withing the accordion control or just a few indented bulleted lists.  The way the accordion control is designed, it doesn't work with the idea of having more than a 2-tier menu.  a 3-tier or more menu would need something other than an accordion control. 

    Of course, having said all of this, you could insert another accordion control within the first to handle the 3rd and/or 4th tiers... but it is then a seperate object and not part of the first at all. other than location on the page of course.

     Does this make sense?

    **************
    * Stoutheart *
    **************
  • Re: Accordion as a sitemap

    11-27-2007, 11:43 AM
    • Loading...
    • whatispunk
    • Joined on 03-06-2007, 10:21 PM
    • Winnipeg
    • Posts 721

    Not at the present, but it could be done.

    Don't know how well it would perform in IE though. It would basically require nested Accordions within each pane. IE already has questionable performance with this control.

    I was using a lot of PNG images to style it though and found that IE doesn't like 1px wide/tall PNGs. It likes larger blocks. Once I increased the size of the repeating PNG background images the performance got a lot better. But it still takes 20% cpu sometimes to expand or shrink a pane.

    If you don't want the expand-a-shrink-a-bility in your sub-sub nodes you could just do it as a <ul> in the pane I guess. But that's probably not the effect you're looking for.

    Remember: mark posts that helped you as the answer to aid future readers

    Why UpdatePanels Are Dangerous
    Why You Should Not Place Your Whole Site In An UpdatePanel
  • Re: Accordion as a sitemap

    05-01-2008, 9:27 AM
    • Loading...
    • Anneleen
    • Joined on 04-14-2008, 11:29 AM
    • Belgium
    • Posts 38

    Hi Thank you for this code it's really useful.  But I wanted to make from the headers of the accordionpane also links

    I changed the code to this

    p.HeaderContainer.Controls.Add(New LiteralControl("<a href='" & RootNodesEnumerator.Current.url & "'><span>" & RootNodesEnumerator.Current.Title & "</span></a>"))

     

    But this doesn't work

    What do I wrong?

     

    Greets

    Anneleen 

  • Re: Accordion as a sitemap

    05-01-2008, 11:23 AM
    • Loading...
    • whatispunk
    • Joined on 03-06-2007, 10:21 PM
    • Winnipeg
    • Posts 721

    Sorry It's been quite a while since I've looked at this code (or used an Accordion) but I remember not being able to do this either.

    If you convert the Accordion Headers to links then how will you open the accordion pane?

    This was one major drawback of using it for site navigation.

    I suppose you could change the code so a mouseover of the header would open the pane and a click would navigate? Or maybe a double click would open and a single would navigate or vice-versa.

    Good luck.

    Remember: mark posts that helped you as the answer to aid future readers

    Why UpdatePanels Are Dangerous
    Why You Should Not Place Your Whole Site In An UpdatePanel
  • Re: Accordion as a sitemap

    05-05-2008, 6:57 AM
    • Loading...
    • Anneleen
    • Joined on 04-14-2008, 11:29 AM
    • Belgium
    • Posts 38

     Hi

     

    Thanks for the answer But what do I need to use to give it the possibility onClick or onMouseOver??  Because I use a href can I still use the onClick method?  If I give already the link?  How Can I fetcht the link then? Do I still have to use the href or do you suggest something else?

     

    Greets
     

  • Re: Accordion as a sitemap

    05-05-2008, 9:49 AM
    • Loading...
    • whatispunk
    • Joined on 03-06-2007, 10:21 PM
    • Winnipeg
    • Posts 721

    Try changing this line:

    p.HeaderContainer.Controls.Add(New LiteralControl("<span>" & RootNodesEnumerator.Current.Title & "</span>"))

    to this:

    p.HeaderContainer.Controls.Add(New