Don't miss out Virtual Happy Hour this Friday (April 26).

Try our conversational search powered by Generative AI!

Navigation using ul/li tags and the PageTree control

Vote:
 
Hi, has anyone used the PageTree control to do a flexible hierarchical navigation using only ul and li elements and styles? I'd like markup looking something like this: I'd like the implementation to be as flexible as possible, theoretically allowing as many levels I'd like. Practically I would strongly discourage anyone from showing more than three levels of depth at any one time (that means it is time to think about your content in another way). If you have the implementation, and also some example styles I'd really appreciate it. If code is needed to do this, I'll be happy with that too :-) /Steve
#12964
Mar 13, 2007 20:25
Vote:
 
Have you tested the standard PageTree which is in the EPiServer examples? This is what it may look like: And there is a bit of code behind this file and in the Masterpage. Unfortunately EPiServer is a huge fan of using . So a lot of EPiCode autogenerates tables and I don't think there is much we can do about that :-( The PageTree should most definitely be
  • tags.
#15166
Mar 15, 2007 10:36
Vote:
 
If you can stand the concept of being tied to a maximum number of levels, you can use nested MenuList controls, example (3 levels)
  • #15167
    Mar 15, 2007 13:38
    Vote:
     
    Limiting the depth is not an option, unfortunately. But interesting solution. I was thinking about using the PageTree, possibly with some code to end the
      tag when the indent changes. I tried, and failed miserably. Just thought I'd check if anyone else has solved this, before I dig into it all over again. Creating a control that walks the PageDataCollection, keeping track of the Indent property, and generate the neccessary tags directly might be the quickest solution. Not as flexible of course. /Steve
    #15168
    Mar 15, 2007 19:48
    Vote:
     
    How will you prevent the EPi code from outputting the Table tags?
    #15169
    Mar 15, 2007 20:28
    Vote:
     
    Not sure what you mean. The PageTree does not output any table tags. It is a template control, and such, it does not output anything at all if I don't tell it to. The sample site does not output any table tags either (/templates/units/menu.ascx). Could you explain a little further? /Steve
    #15170
    Mar 15, 2007 21:12
    Vote:
     
    I have been thinking quite a lot on how to make a flexible reusable structured list control. Hopefully you can use it, as an inspiration at least. Regards, HAXEN using System; using System.Reflection; using System.Web.UI; using System.Web.UI.HtmlControls; using EPiServer; using EPiServer.Core; using EPiServer.Security; namespace KnowIT.WebControls { /// /// /// public class PageTreeList : EPiServer.WebControls.PageTreeData, INamingContainer { private ITemplate _itemTemplate = null; private ITemplate _rootTemplate = null; private ITemplate _headerTemplate = null; private ITemplate _footerTemplate = null; private PageDataCollection _parentChain = null; public PageTreeList() { } public string ContainerID { set { ViewState["ContainerID"] = value; } get { return ViewState["ContainerID"] != null ? ViewState["ContainerID"].ToString() : ""; } } public string CssClass { set { ViewState["CssClass"] = value; } get { return ViewState["CssClass"] != null ? ViewState["CssClass"].ToString() : ""; } } public string LastItemClass { set { ViewState["LastItemClass"] = value; } get { return ViewState["LastItemClass"] != null ? ViewState["LastItemClass"].ToString() : ""; } } public string FirstItemClass { set { ViewState["FirstItemClass"] = value; } get { return ViewState["FirstItemClass"] != null ? ViewState["FirstItemClass"].ToString() : ""; } } public string SelectedClass { set { ViewState["SelectedClass"] = value; } get { return ViewState["SelectedClass"] != null ? ViewState["SelectedClass"].ToString() : ""; } } public string ExpandedClass { set { ViewState["ExpandedClass"] = value; } get { return ViewState["ExpandedClass"] != null ? ViewState["ExpandedClass"].ToString() : ""; } } public string AfterSelectedClass { set { ViewState["AfterSelectedClass"] = value; } get { return ViewState["AfterSelectedClass"] != null ? ViewState["AfterSelectedClass"].ToString() : ""; } } public string BeforeSelectedClass { set { ViewState["BeforeSelectedClass"] = value; } get { return ViewState["BeforeSelectedClass"] != null ? ViewState["BeforeSelectedClass"].ToString() : ""; } } public string ContainerTag { set { ViewState["ContainerTag"] = value; } get { return ViewState["ContainerTag"] != null ? ViewState["ContainerTag"].ToString() : "ul"; } } protected virtual HtmlGenericControl CreateContainerControl(int level) { string cssClass = ""; HtmlGenericControl listContainer = new HtmlGenericControl(ContainerTag); if ((level == 0 & ShowRootPage) | (level == 1 & !ShowRootPage)) { cssClass = AppendClass(cssClass, CssClass); if (ContainerID.Length > 0) listContainer.Attributes.Add("id", ContainerID); } if (cssClass.Length > 0) listContainer.Attributes.Add("class", cssClass); return listContainer; } protected virtual string AppendClass(string currentClass, string addClass) { return AppendClass(currentClass, addClass, null); } protected virtual string AppendClass(string currentClass, string addClass, PageTreeReader reader) { if (addClass.Length > 0) { if (currentClass.IndexOf(addClass) < 0) { if (currentClass.Length > 0) currentClass += " "; if(reader != null) if ((addClass.EndsWith("_lvl")) | (addClass.EndsWith("_level")) | (addClass.EndsWith("_lv"))) addClass += reader.CurrentIndent.ToString(); currentClass += addClass; } } return currentClass; } protected virtual bool IsInParentChain(PageData page) { return ParentChain().Exists(page.PageLink); } protected virtual PageDataCollection ParentChain() { if (_parentChain == null) { _parentChain = new PageDataCollection(); PageData page = this.CurrentPage; while (page.ParentLink != PageReference.EmptyReference) { _parentChain.Insert(0, page); page = Global.EPDataFactory.GetPage(page.ParentLink, AccessControlList.NoAccess); } } return _parentChain; } protected virtual HtmlGenericControl CreateListControl(PageTreeReader page) { string cssClass = ""; HtmlGenericControl listItem = new HtmlGenericControl("li"); if (page.IndentJump > 0) cssClass = AppendClass(cssClass, FirstItemClass); if (page.Page.PageLink.CompareToIgnoreWorkID(base.CurrentPage.PageLink)) cssClass = AppendClass(cssClass, SelectedClass, page); if (IsInParentChain(page.Page)) cssClass = AppendClass(cssClass, ExpandedClass, page); if (cssClass.Length > 0) { listItem.Attributes.Add("class", cssClass); } return listItem; } protected virtual void AppendToListControl(HtmlGenericControl listItem, string propertyName) { string cssClass = ""; if (listItem.Attributes["class"] != null && listItem.Attributes["class"] != "") cssClass = listItem.Attributes["class"]; PropertyInfo property = this.GetType().GetProperty(propertyName); if( property != null ) cssClass = AppendClass(cssClass, property.GetValue(this, null).ToString()); if (cssClass.Length > 0) listItem.Attributes.Add("class", cssClass); } protected virtual void CreateContainer(PageTreeReader reader, Control appendTo) { Control workingControl = appendTo; HtmlGenericControl listContainer = null; HtmlGenericControl listItem = null; int selectedLevel = -1; while (reader.Read()) { if (ShowRootPage && reader.Pages.Find(reader.Page.PageLink) == 0) { listContainer = CreateContainerControl(reader.CurrentIndent); appendTo.Controls.Add(listContainer); } else { if (reader.IndentJump > 0) { listContainer = CreateContainerControl(reader.CurrentIndent); if (listItem == null) appendTo.Controls.Add(listContainer); else listItem.Controls.Add(listContainer); } else if (reader.IndentJump < 0) { for (int i = reader.IndentJump; i < 0; i++) { if (listItem != null) AppendToListControl(listItem, "LastItemClass"); listItem = listContainer.Parent as HtmlGenericControl; listContainer = listItem.Parent as HtmlGenericControl; } } } if (reader.Page.PageLink.CompareToIgnoreWorkID(base.CurrentPage.PageLink)) if (listContainer != null && listContainer.Controls.Count > 0) AppendToListControl((HtmlGenericControl)listContainer.Controls[listContainer.Controls.Count - 1], "BeforeSelectedClass"); listItem = CreateListControl(reader); if (selectedLevel == reader.CurrentIndent) { AppendToListControl(listItem, "AfterSelectedClass"); selectedLevel = -1; } if (reader.Page.PageLink.CompareToIgnoreWorkID(base.CurrentPage.PageLink)) selectedLevel = reader.CurrentIndent; if(listContainer != null) listContainer.Controls.Add(listItem); PageTemplateContainer item = new PageTemplateContainer(reader.Page); if (ShowRootPage && reader.Pages.Find(reader.Page.PageLink) == 0) { this.RootTemplate.InstantiateIn(item); } else { this.ItemTemplate.InstantiateIn(item); } listItem.Controls.Add(item); } if (listItem != null) AppendToListControl(listItem, "LastItemClass"); } protected override void CreateChildControls() { if (SetDefaultTemplates()) { PageDataCollection pages = this.GetPages(); if (pages.Count > 0) { PageTreeReader reader = new PageTreeReader(pages); PageReference currentPageLink = base.CurrentPage.PageLink; PageData basePage = null; if (this.PageLink != PageReference.EmptyReference) { basePage = GetPage(this.PageLink); } else if (pages[0].Indent == 0) { basePage = pages[0]; } if (this.HeaderTemplate != null) { Control header = new PageTemplateContainer(basePage); this.HeaderTemplate.InstantiateIn(header); this.Controls.Add(header); } CreateContainer(reader, this); if (this.FooterTemplate != null) { Control footer = new PageTemplateContainer(basePage); this.FooterTemplate.InstantiateIn(footer); this.Controls.Add(footer); } } } } protected virtual bool SetDefaultTemplates() { if (this.ItemTemplate == null) return false; if (this.RootTemplate == null) this.RootTemplate = this.ItemTemplate; return true; } [TemplateContainer(typeof(PageTemplateContainer)), PersistenceMode(PersistenceMode.InnerProperty)] public ITemplate RootTemplate { set { _rootTemplate = value; } get { return _rootTemplate; } } [TemplateContainer(typeof(KnowIT.WebControls.PageTemplateContainer)), PersistenceMode(PersistenceMode.InnerProperty)] public ITemplate ItemTemplate { set { _itemTemplate = value; } get { return _itemTemplate; } } [TemplateContainer(typeof(KnowIT.WebControls.PageTemplateContainer))] public ITemplate HeaderTemplate { set { _headerTemplate = value; } get { return _headerTemplate; } } [TemplateContainer(typeof(KnowIT.WebControls.PageTemplateContainer))] public ITemplate FooterTemplate { set { _footerTemplate = value; } get { return _footerTemplate; } } } } HTML use
    #15171
    Mar 16, 2007 10:06
    Vote:
     
    Steve, you are absolutly right. My bad. The PageTree does not output any tags. I have assumed my colleague had more or lessed used EPiCode (as he normally does) and therefore the table tags was standard EPiServer. Phu! What a relief :-D Now, here is a thought I have been playing with. It's probably not he quickest way of displying menus (or the smartest), but in theory; Using a ajax component that triggers the GetChildren() function each time you want to expand a menu item. Just playing with the thought :)
    #15172
    Mar 16, 2007 10:54
    Vote:
     
    Til: Håkan Alexander (HAXEN) Jeg er meget interesseret i at se din kode i funktion. Hvordan ser dit register-tag ud og jeg er lidt i tvivl om hvor du får din PageTemplateContainer fra. Er det fra EPiServer eller fra System.etellerandet? Endeligt skal jeg høre ang. den Property du benytter i din HTML (På aspx siden) Skal det være en EPiServer eller mangler der nogle deklaratiner et sted?
    #15173
    Oct 03, 2007 10:25
    Vote:
     
    Oups. Translation. To: Håkan Alexander (HAXEN) Im very interested to see your PageTreeList in action. How do your Register-tag look like? I am a little confused about where you get your PageTemplateContainer from. Either EPiServer.WebControls or System.something? Finally i need to hear about the property-tag you use. Is it derived from EPiServer class or is some declaration missing?
    #15174
    Oct 03, 2007 10:30
    * You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.