I'm building a site in Orchard that will have around 130 pages. We've setup a Navigation menu called "Main Menu" with all of our pages setup in a hierarchy (the example I'm showing is from my sandbox site and not our actual development site).
In my "AsideFirst" zone on our default widget layer, I have added a menu widget that references the above "Main Menu." The start level is set to 0, and the levels to display is set to 0. On the front end, using the shape tracer, I have created an alternate called "Parts.MenuWidget-AsideFirst.cshtml."
The menu renders just fine, however, I'm not sure where to start on modifying the core "Navigation" driver to allow me to display only the pages relative to the page that I'm on. For instance, if I'm on the page "Testing II" I'd like navigation that renders the following HTML:
<ul>
<li><a href="/testing-i/">Testing I</a></li>
<li>
<a href="/testing-ii/" class="active">Testing II</a>
<ul>
<li><a href="/bark-bark/"></a></li>
</ul>
</li>
<li><a href="/testing-iii/">Testing III</a>
</ul>
The alternate that I'm using has the following code. This works if I'm within any of the top level sections, but not the deeper levels. The following code is not the Orchard way to do things, so I'd like to know how I should achieve this properly through drivers and handlers - especially since this isn't accomplishing what I need it to anyway.
@{
var navTag = Tag(Model, "nav");
navTag.AddCssClass("nav-sidebar");
@navTag.StartElement;
var ulTag = Tag(Model, "ul");
@ulTag.StartElement
// Model is Model.Menu from the layout (Layout.Menu)
var items = getSectionItems((IList<dynamic>)Enumerable.Cast<dynamic>(Model.Menu.Items));
// Add First and Last Classes
if (items.Any())
{
items[0].Classes.Add("first");
items[items.Count - 1].Classes.Add("last");
}
// List Items
foreach (var listModel in items)
{
// Current URL
string requestUrl = getRequestUrl();
string modelUrl = getModelUrl(listModel);
bool showMenu = false;
if (isActivePage(requestUrl, modelUrl))
{
listModel.Classes.Add("active");
showMenu = true;
}
if (showMenu)
{
// Sub Items
var listItems = Enumerable.Cast<dynamic>((System.Collections.IEnumerable)listModel);
if (listItems.Any())
{
listModel.Classes.Add("dropdown");
}
// List Tag
var liTag = Tag(listModel, "li");
@liTag.StartElement;
listModel.Metadata.Alternates.Clear();
listModel.Metadata.Type = "MenuItemLink";
// Top Level Nav Items
string className = System.Text.RegularExpressions.Regex.Replace(listModel.Href, "[^A-Za-z0-9-]", "");
className = className.Length > 0 ? className : "home";
<a href="@listModel.Href" class="@className">@listModel.Text</a>
if (listItems.Any())
{
<ul>
@DisplayChildren(listModel)
</ul>
}
@liTag.EndElement;
}
}
@ulTag.EndElement;
@navTag.EndElement;
}
@functions{
private IList<dynamic> getSectionItems(IList<dynamic> sectionItems)
{
return sectionItems;
}
private string getRequestUrl()
{
return Request.Path.Replace(Request.ApplicationPath, string.Empty).TrimEnd('/').ToUpperInvariant();
}
private string getModelUrl(dynamic listModel)
{
return listModel.Href.Replace(Request.ApplicationPath, string.Empty).TrimEnd('/').ToUpperInvariant();
}
private bool isActivePage(string requestUrl, string modelUrl)
{
if (requestUrl == modelUrl || (!string.IsNullOrEmpty(modelUrl) && requestUrl.StartsWith(modelUrl + "/")))
{
return true;
}
return false;
}
}