views:

245

answers:

2

I've had a good look through a load of MS documentation only to find a tree view like structure to the use of sitemaps. I don't suppose anyone's aware of how it's possible to have a folder-like structure for sitemap navigation? Take for example a structure as follows

Home
   About
      Me.aspx
      MyFamily.aspx
      MyPets.aspx
   Contact
      Telephone.aspx
      Email.aspx
 Disclaimer.aspx

The "About" and "Contact" would be folders, but the sitemap is never hierarchical on a single page. So, I would have my root page with two menu items, one would be "Home" which acts like a folder to drill down into the about and contact menus, and the other is a link to the page for the disclaimer. I want to be able to click on Home which will reload the menu with the links for "About" and "Contact" and hide "Home" and "Disclaimer" altogether.

Home >
Disclaimer

Then click on home and you would get

About >
Contact >

Then when clicking on about you'd get

Me
My Family
My Pets

Every menu would have an "up" menu to come back out a folder.

I can't see there being an easy solution, but at the moment we use static html pages that are in different folders all over our web application. This is something that needs changing as you can well imagine.

Any ideas?

EDIT

I've had to come up with a VB.NET solution

<script runat="server">
  Private Function GetSecondaryNavItems() As String
    Dim sRet As String = ""

    Dim oCurrNode As System.Web.SiteMapNode = Nothing
    Dim oCurrParentNode As System.Web.SiteMapNode = Nothing

    'Dim sCurrPage As String = GetURL(Request.ServerVariables("SCRIPT_NAME").ToLower())
    Dim sCurrPage As String = GetURL(HttpContext.Current.Request.ServerVariables("SCRIPT_NAME").ToLower())
    oCurrNode = GetCurrentNode(sCurrPage, SiteMap.RootNode)

    If Not oCurrNode Is Nothing Then
      oCurrParentNode = oCurrNode.ParentNode
    End If

    If Not oCurrParentNode Is Nothing Then
      If Not oCurrParentNode Is SiteMap.RootNode Then
        sRet += "Parent Folder Link"

        If Not oCurrNode Is Nothing Then
          For Each oChild As SiteMapNode In oCurrParentNode.ChildNodes
            sRet += "Link for child"
          Next
        End If
      End If
    End If

    Return sRet
  End Function

  Private Function GetURL(ByVal fullURL As String) As String
    Return fullURL.Substring(fullURL.LastIndexOf("/"))
  End Function

  Private Function GetCurrentNode(ByVal _sCurrentPageURL As String, ByVal _oNode As SiteMapNode) As SiteMapNode
    Dim oNodeRet As SiteMapNode = Nothing

    For Each oNodeCheck As SiteMapNode In _oNode.ChildNodes
      If oNodeCheck.HasChildNodes = True Then
        oNodeRet = GetCurrentNode(_sCurrentPageURL, oNodeCheck)
      End If

      If oNodeRet Is Nothing Then
        Exit For
      End If

      Dim sURL As String = oNodeCheck.Url.ToLower()
      Dim iPos As Integer = sURL.IndexOf("?")

      If iPos > 0 Then
        sURL = sURL.Substring(0, iPos)
      End If

      iPos = sURL.LastIndexOf("/")

      If iPos > 0 Then
        sURL = sURL.Substring(iPos)
      End If

      If sURL = _sCurrentPageURL Then
        oNodeRet = oNodeCheck
        Exit For
      End If
    Next

    Return oNodeRet
  End Function
</script>

This is in the master page file directly (temporary, I'll place it in the code behind model later).

I've then got this in the body

<div id="sidebar">
  <%= GetSecondaryNavItems() %>
</div>

Again, temporarily just to test. It doesn't actually output anything but then I'm thinking my GetURL definition is incorrect. I was assuming it was just getting the actual file? I could be very wrong though :)

EDIT EDIT: For some reason I'm not getting any output, so I thought it was my sitemap. I'll need to debug it but I'm remoting in at the moment so it's quite slow ;)

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
  <siteMapNode url="Accounts/Default.aspx" title="Accounts"  description="Accounts">
    <siteMapNode url="Accounts/Test.aspx" title="Client Balances" description="Client Balances">
      <siteMapNode url="Hello.aspx" title="Hello"  description="rarar" />
      <siteMapNode url="Hiya.aspx" title="Hiya"  description="rarar" />
    </siteMapNode>
    <siteMapNode url="Test.aspx" title="Test"  description="rarar" />
  </siteMapNode>
</siteMap>

Here's the example sitemap.

+1  A: 

You could still use the Sitemap.sitemap file to control your navigation, but you wouldn't use any of the built-in controls in asp.net to achieve this. I just did almost this very thing on a site I just finished.

Make all of your pages inherit from a base page class (or use master pages, either way you'll only have 1 copy of your code.)

Create a div or span on each page, named something appropriate (divNav or spnNav or whatever).

In your base page, on page load, loop through all the sitemap nodes to find the current page's node. This needs to be a recursive call.

 // Pass the current page url, all the way through the .aspx.  In other words, do NOT pass any kind of 
 // query string.
 private SiteMapNode GetCurrentNode(string _sCurrentPageURL, SiteMapNode _oNode)
 {
     SiteMapNode oNodeRet = null;

     foreach (SiteMapNode oNodeCheck in _oNode.ChildNodes)
     {
         if (oNodeCheck.HasChildNodes == true)
         {
             oNodeRet = GetCurrentNode(_sCurrentPageURL, oNodeCheck);
         }

         if (oNodeRet != null)
             break;

         string sUrl = oNodeCheck.Url.ToLower();
         int iPos = sUrl.IndexOf("?");
         if (iPos > 0)
             sUrl = sUrl.Substring(0, iPos);
         iPos = sUrl.LastIndexOf("/");
         if (iPos > 0)
             sUrl = sUrl.Substring(iPos);

         if (sUrl == _sCurrentPageURL)
         {
             oNodeRet = oNodeCheck;
             break;
         }
     }
     return oNodeRet;
 }

Once you have the current node, get its parent.

Add a link (the "up menu to come back out a folder" as you called it).

Then do a foreach(SiteMapNode in parent.ChildNodes)

Add a link for each of the children.

So, our main call, that we called on every page load, was like this:

 public string GetSecondaryNavItems()
 {
     string sRet = "";

     // Get the node that matches most of this url...
     System.Web.SiteMapNode oCurrNode = null;
     System.Web.SiteMapNode oCurrParentNode = null;

     string sCurrPage = GetURL(Request.ServerVariables["SCRIPT_NAME"].ToLower());

     oCurrNode = GetCurrentNode(sCurrPage, SiteMap.RootNode);

     if(oCurrNode != null)
         oCurrParentNode = oCurrNode.ParentNode;

     if(oCurrParentNode != null)
        if(oCurrParentNode != SiteMap.RootNode)
         sRet += "Parent Folder link";

   if(oCurrNode != null)
   {
         foreach (System.Web.SiteMapNode oChild in oCurrParentNode.ChildNodes)
         {
           sRet += "Link for child";
        }
     }
 }

I have to tell you that the code above is part copied and part freehanded by me. But this should give you a good start, I would think.

EDIT: So sorry! Here is the GetURL proc...

    public string GetURL(string _sURL)
    {
        string sRet = _sURL;

        int iPos = sRet.IndexOf("?");
        if (iPos > 0)
            sRet = sRet.Substring(0, iPos);
        iPos = sRet.LastIndexOf("/");
        if (iPos > 0)
            sRet = sRet.Substring(iPos);

        return sRet;
    }
Matt Dawdy
If you just check my edit when you've got the time that'd be great. Cheers
Kezzer
I just added the GetURL in C# for you, but what you had probably should have worked, since I bet you aren't using querystrings on those pages. I'll take another look.
Matt Dawdy
I can't seem to find the issue with it, but nothing gets output whatsoever, although it's probably to do with my sitemap (I've put it in the edit of my post). I'll have to check tomorrow when I'm at work again unfortunately. Cheers for the snippet, that makes perfect sense.
Kezzer
hey Kezzer -- I'll take a look at this tomorrow, but I suspect the problem is probably that you have a couple of URLs that are under an Accounts folder. I'm not sure my code accounts for that. I'll use your sitemap tomorrow and see what I can find.
Matt Dawdy
It's quite literally a test sitemap, if there's something logically wrong with the sitemap just give me a shout. Our sitemap is really quite large and has a maximum depth of probably 5 or 6. Cheers
Kezzer
A: 

Whilst I'm not supposed to respond I'd actually ask something further to this. Is it possible to do the exact same thing but using a page which is composed of simply <ul> and <li> elements? The reason why I ask is because our "sitemap" is actually a tad more advanced in terms of both security and functionality. The menus we run actually have dynamic drop down lists with input boxes, this is something that can't be duplicated in a sitemap.

So, the idea is to do the exact same thing except with a

<ul>
   <li>
      <ul>
         <li></li>
      </ul>
   </li>
   <li></li>
   <li></li>
</ul>

structure instead. The root node would have to have a runat="server" on it, that way you could traverse all child elements perhaps? This way I can place anything within my <li> and </li> elements.

Our security is quite sporadic too, something a sitemap doesn't have the kind of granular control we're looking for either.

Kezzer