show path back to root node

Last post 05-08-2006 3:39 PM by bttrflii. 4 replies.

Sort Posts:

  • show path back to root node

    05-05-2006, 4:45 PM
    • Member
      590 point Member
    • bttrflii
    • Member since 06-28-2005, 4:33 PM
    • Posts 132
    what's the best way to set a css class of, for example, "active" on the <li> leading from the current page's node back to the root?  for example someone is viewing page 1.2.4 as in chapter 1, section 2, page 4.  how do i give those three nodes this "active" class?

    the menu might look something like this:

    chapter 1
        - section 1
           - page 1
           - page 2
       -  section 2
            - page 1
           - page 2
           - page 3
           - page 4
        - section 3
    chapter 2
    ~ cj
  • Re: show path back to root node

    05-05-2006, 6:59 PM
    • Contributor
      3,298 point Contributor
    • Russ Helfand
    • Member since 09-14-2005, 6:22 PM
    • Groovybits.com
    • Posts 741

    You could add some logic into the BuildItem method in TreeViewAdapter.cs (or vb).  That file contains the logic that creates the adapted HTML for the TreeView control.  You can find that file in App_Code\Adapters.

    Presumably, you would want to test (in BuildItem) to see if a node in the tree conformed to some special condition (like it corresponded to the active page) and then add another class to its class attribute value.  Remember that you can have multiple classes listed in the class attribute by separating them with spaces.

    The only problem with that approach is that it tends to make the TreeView adapter "know" things that ideally it shouldn't have to know about -- like that your site likes to style nodes in the tree specially when they correspond to the active page.  Still, it may be the best approach for you in this case.

    If you wanted to get a little more fancy you could add an expando property to the TreeView control, something like (MarkActive).  The adapter could look for that expando property on the control and use its value to figure out if particular nodes should be marked (using an extra CSS class) as being "active."

    Expando properties are simply extra (custom) properties that you add to any ASP.NET control.  The kit uses an expando property called CssSelectorClass.  So, you can follow its usage logic to see how you might add your own expando, MarkActive.

    If you get stuck, post something here.  Maybe others in the community can help you figure this out, too.

    -Russ-

    Russ Helfand
    Groovybits.com
  • Re: show path back to root node

    05-08-2006, 9:54 AM
    • Member
      590 point Member
    • bttrflii
    • Member since 06-28-2005, 4:33 PM
    • Posts 132
    thank you so much for replying russ.  :)

    the problem i've had with adding logic to this control is that while it looks simple, it boggles my mind as to how to get it to do what i want.  part of my problem is that the control doesn't know what page it's on (and because of that, doesn't know the path to root either) until it actually gets to the url that matches the page.  by the time the control reaches that page in its logic, it has already coded for the node's parents and i have no idea how to add a css class back to the things the writer has already written.

    &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;siteMapNode title="Billing" url="~/billing/default.aspx"&gt;
    &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;siteMapNode title="Setup"&gt;
    &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;siteMapNode url="~/billing/listbillmessages.aspx"&nbsp;&nbsp;&nbsp; title="List Enabled Bill Messages"/&gt;
    &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;siteMapNode url="~/billing/newbillmessage.aspx"&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; title="Add a new Bill Message"/&gt;[snip]


    because of how the path to the root is defined, i can't simply check to see if i'm going along the correct *folder* path and adding an "active" class that way.  i need to find the current page's corresponding menu item and backtrack.  to say it a bit more accurately, finding the current page and backtracking is the only way i, as a newbie javascripter and c#er, know how to do it.

    i thought that what i wanted should be absurdly easy because i had a "SelectedNodeStyle-CssClass" property in the treeview control.  if this doesn't do what i'm asking (and it sure hasn't), i would definitely appreciate some guidance on what to edit and where to edit it in the treeview adapter.  i'm hopelessly out of my depth.
    ~ cj
  • Re: show path back to root node

    05-08-2006, 9:59 AM
    • Member
      590 point Member
    • bttrflii
    • Member since 06-28-2005, 4:33 PM
    • Posts 132
    that code snippet was a mess.  sorry about that.  here it is again without the code look applied to it:
     
    <siteMapNode title="Billing" url="~/billing/default.aspx">
    	<siteMapNode title="Setup" url="~/billing/setup">
    		<siteMapNode url="~/billing/listbillmessages.aspx"	title="List Enabled Bill Messages"/>
    		<siteMapNode url="~/billing/newbillmessage.aspx"	title="Add a new Bill Message"/>
    
     
    ~ cj
  • Re: show path back to root node

    05-08-2006, 3:39 PM
    • Member
      590 point Member
    • bttrflii
    • Member since 06-28-2005, 4:33 PM
    • Posts 132
    the good news is that i muddled and fiddled until something started working.  :)  the bad news is that i probably did this in a very that-is-SO-not-even-right way, but since i don't have anything else to go off of, my way is all i've got.  if someone else wanted the functionality more than pretty code, here is my app_code/adapters/treeview.cs code in its entirety.  hopefully it will spark something for someone else, who will post back a better method than this.  (hint hint)

     
    using System;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace CSSFriendly
    {
        public class TreeViewAdapter : System.Web.UI.WebControls.Adapters.HierarchicalDataBoundControlAdapter
        {
            public TreeNode activeNode;
            public bool isActivePath = false;
    
            public TreeViewAdapter()
            {
                //
            }
    
            protected override void OnInit(EventArgs e)
            {
                base.OnInit(e);
                RegisterScripts();
            }
    
            private void RegisterScripts()
            {
                Utility.RegisterScripts(Page);
                Page.ClientScript.RegisterClientScriptInclude(GetType(), GetType().ToString(), Page.ResolveUrl("~/includes/adapters/treeview.js"));
            }
    
            protected override void RenderBeginTag(HtmlTextWriter writer)
            {
                if ((Control != null) && (Control.Attributes["CssSelectorClass"] != null) && (Control.Attributes["CssSelectorClass"].Length > 0))
                {
                    writer.WriteLine();
                    writer.WriteBeginTag("div");
                    writer.WriteAttribute("class", Control.Attributes["CssSelectorClass"]);
                    writer.Write(HtmlTextWriter.TagRightChar);
                    writer.Indent++;
                }
    
                writer.WriteLine();
                writer.WriteBeginTag("div");
                writer.WriteAttribute("class", Control.Attributes["CssSelectorClass"] + "-inside");
                writer.Write(HtmlTextWriter.TagRightChar);
            }
    
            protected override void RenderEndTag(HtmlTextWriter writer)
            {
                writer.WriteEndTag("div");
    
                if ((Control != null) && (Control.Attributes["CssSelectorClass"] != null) && (Control.Attributes["CssSelectorClass"].Length > 0))
                {
                    writer.Indent--;
                    writer.WriteLine();
                    writer.WriteEndTag("div");
                }
    
                writer.WriteLine();
            }
    
            protected override void RenderContents(HtmlTextWriter writer)
            {
                TreeView treeView = Control as TreeView;
                if (treeView != null)
                {
                    AssureAllNodesAreBuilt(treeView);
                    activeNode = treeView.SelectedNode;
    
                    writer.Indent++;
                    BuildItems(treeView.Nodes, true, true, writer);
                    writer.Indent--;
                    writer.WriteLine();
                }
            }
    
            private void BuildItems(TreeNodeCollection items, bool isRoot, bool isExpanded, HtmlTextWriter writer)
            {
                if (items.Count > 0)
                {
                    writer.WriteLine();
    
                    writer.WriteBeginTag("ol");
                    if (!isExpanded)
                    {
                        writer.WriteAttribute("class", "menu-hide");
                    }
                    writer.Write(HtmlTextWriter.TagRightChar);
                    writer.Indent++;
    
                    foreach (TreeNode item in items)
                    {
                        BuildItem(item, writer);
                    }
    
                    writer.Indent--;
                    writer.WriteLine();
                    writer.WriteEndTag("ol");
                }
            }
    
            private void BuildItem(TreeNode item, HtmlTextWriter writer)
            {
                TreeView treeView = Control as TreeView;
                if ((treeView != null) && (item != null) && (writer != null))
                {
                    isActivePath = false;
                    if (IsActivePath(item)) // cj
                        item.Expand();
    
                    #region [start tags]
                    writer.WriteLine();
                    writer.WriteBeginTag("li");
    
                    writer.WriteAttribute("class", GetNodeClass(item, isActivePath)); // cj
                    writer.Write(HtmlTextWriter.TagRightChar);
                    writer.Indent++;
                    writer.WriteLine();
                    #endregion
    
                    #region [expand button]
                    if (item.ChildNodes.Count > 0)
                    {
                        writer.WriteBeginTag("span");
                        writer.WriteAttribute("class", ((item.Expanded == true) ? "menu-collapse" : "menu-expand"));
                        writer.WriteAttribute("onclick", "ExpandCollapse__AspNetTreeView(this)");
                        writer.Write(HtmlTextWriter.TagRightChar);
                        writer.Write("&nbsp;");
                        writer.WriteEndTag("span");
                        writer.WriteLine();
                    }
                    #endregion
    
                    if (item.NavigateUrl.Length > 0)
                    {
                        #region [create link]
                        writer.WriteBeginTag("a");
                        if (item.Parent == null)
                            writer.WriteAttribute("class", "chapter");
    
                        writer.WriteAttribute("href", Page.ResolveUrl(item.NavigateUrl));
                        if (item.Target.Length > 0)
                        {
                            writer.WriteAttribute("target", item.Target);
                        }
                        if (item.ToolTip.Length > 0)
                        {
                            writer.WriteAttribute("title", item.ToolTip);
                        }
                        else if (treeView.ToolTip.Length > 0)
                        {
                            writer.WriteAttribute("title", treeView.ToolTip);
                        }
                        writer.Write(HtmlTextWriter.TagRightChar);
                        writer.Indent++;
                        writer.WriteLine();
                        #endregion
                    }
                    else
                    {
                        #region [parent - no link]
                        writer.WriteBeginTag("span");
                        if (item.ChildNodes.Count > 0)
                        {
                            writer.WriteAttribute("class", "menu-clickable");
                            writer.WriteAttribute("onclick", "ExpandCollapse__AspNetTreeView(this.parentNode.getElementsByTagName('span')[0])");
                        }
                        else
                        {
                            writer.WriteAttribute("class", "menu-nothing");
                        }
                        writer.Write(HtmlTextWriter.TagRightChar);
                        writer.Indent++;
                        writer.WriteLine();
                        #endregion
                    }
    
                    #region [set child graphic]
                    string imgSrc = GetImageSrc(treeView, item);
                    if (imgSrc.Length > 0)
                    {
                        writer.WriteBeginTag("img");
                        writer.WriteAttribute("src", Page.ResolveUrl(imgSrc));
                        writer.WriteAttribute("alt", item.ToolTip.Length > 0 ? item.ToolTip : (treeView.ToolTip.Length > 0 ? treeView.ToolTip : item.Text));
                        writer.Write(HtmlTextWriter.SelfClosingTagEnd);
                    }
                    #endregion
    
                    writer.Write(item.Text);
    
                    #region [end tags and insert children]
                    if (item.NavigateUrl.Length > 0)
                    {
                        writer.Indent--;
                        writer.WriteLine();
                        writer.WriteEndTag("a");
                    }
                    else
                    {
                        writer.Indent--;
                        writer.WriteLine();
                        writer.WriteEndTag("span");
                    }
    
                    if ((item.ChildNodes != null) && (item.ChildNodes.Count > 0))
                    {
                        BuildItems(item.ChildNodes, false, (item.Expanded == true), writer);
                    }
    
                    writer.Indent--;
                    writer.WriteLine();
                    writer.WriteEndTag("li");
                    #endregion
                }
            }
    
            private string GetNodeClass(TreeNode item, bool isActive)
            {
                string value = Control.Attributes["CssSelectorClass"] + "-leaf";
    
                if (item != null)
                {
                    if (item.Depth == 0)
                    {
                        if (item.ChildNodes.Count > 0)
                        {
                            value = Control.Attributes["CssSelectorClass"] + "-root " + Control.Attributes["CssSelectorClass"] + "-parent";
                        }
                        else
                        {
                            value = Control.Attributes["CssSelectorClass"] + "-root " + Control.Attributes["CssSelectorClass"] + "-leaf";
                        }
                    }
                    else if (item.ChildNodes.Count > 0)
                    {
                        value = Control.Attributes["CssSelectorClass"] + "-parent";
                    }
                }
    
                if (isActive) // cj
                {
                    TreeView treeView = Control as TreeView;  // find me - this is kind of redundant
                    value = treeView.SelectedNodeStyle.CssClass + " " + value;
                }
    
                return value;
            }
    
            private string GetImageSrc(TreeView treeView, TreeNode item)
            {
                string imgSrc = "";
    
                if ((treeView != null) && (item != null))
                {
                    imgSrc = item.ImageUrl;
    
                    if (imgSrc.Length == 0)
                    {
                        if (item.Depth == 0)
                        {
                            if ((treeView.RootNodeStyle != null) && (treeView.RootNodeStyle.ImageUrl.Length > 0))
                            {
                                imgSrc = treeView.RootNodeStyle.ImageUrl;
                            }
                        }
                        else
                        {
                            if (item.ChildNodes.Count == 0)
                            {
                                if ((treeView.LeafNodeStyle != null) && (treeView.LeafNodeStyle.ImageUrl.Length > 0))
                                {
                                    imgSrc = treeView.LeafNodeStyle.ImageUrl;
                                }
                            }
                            else if ((treeView.ParentNodeStyle != null) && (treeView.ParentNodeStyle.ImageUrl.Length > 0))
                            {
                                imgSrc = treeView.ParentNodeStyle.ImageUrl;
                            }
                        }
                    }
    
                    if ((imgSrc.Length == 0) && (treeView.LevelStyles != null) && (treeView.LevelStyles.Count > item.Depth))
                    {
                        if (treeView.LevelStyles[item.Depth].ImageUrl.Length > 0)
                        {
                            imgSrc = treeView.LevelStyles[item.Depth].ImageUrl;
                        }
                    }
                }
    
                return imgSrc;
            }
    
            private void AssureAllNodesAreBuilt(TreeView treeView)
            {
                if (treeView != null)
                {
                    int currentDepth = treeView.ExpandDepth;
                    treeView.ExpandDepth = -1;
                    treeView.ExpandAll();
                    treeView.ExpandDepth = currentDepth;
                    if (treeView.ExpandDepth > -1)
                    {
                        treeView.CollapseAll();
                        ExpandToDepth(treeView.Nodes, treeView.ExpandDepth);
                    }
                }
            }
    
            static public void ExpandToDepth(TreeNodeCollection nodes, int expandDepth)
            {
                foreach (TreeNode node in nodes)
                {
                    if (node.Depth < expandDepth)
                    {
                        node.Expand();
                        ExpandToDepth(node.ChildNodes, expandDepth);
                    }
                }
            }
    
            public bool IsActivePath(TreeNode node) // cj
            {
                foreach (TreeNode child in node.ChildNodes)
                {
                    IsActivePath(child);
                }
    
                if (node.Equals(activeNode))
                    isActivePath = true;
    
                return isActivePath;
            }
        }
    }
    
    [note: i didn't take out any of my personal comments since most of the places i put them are where i changed code for this "active" project and they might help you find most of the different lines.]
    ~ cj
Page 1 of 1 (5 items)