Skip to content

Commit 7ffa765

Browse files
author
Warren Buckley
authored
Merge pull request #31 from umbraco-community/feature/is-active-page
Adds our-active-class Taghelper
2 parents 46586b9 + 659d89f commit 7ffa765

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
using Microsoft.AspNetCore.Razor.TagHelpers;
2+
using System.Text.Encodings.Web;
3+
using Umbraco.Cms.Core.Web;
4+
using Umbraco.Extensions;
5+
using Microsoft.AspNetCore.Mvc.TagHelpers;
6+
using System;
7+
8+
namespace Our.Umbraco.TagHelpers
9+
{
10+
/// <summary>
11+
/// An attribute TagHelper that only works with <a> tags
12+
///
13+
/// Applying the attribute our-is-active-page="navi-active"
14+
/// Will apply the CSS class name navi-active to the class attribute
15+
/// if the value in the href of the <a> compared to the page being rendered
16+
/// is the current page or part of an ancestor
17+
/// </summary>"
18+
[HtmlTargetElement("*", Attributes = tagHelperAttributes)]
19+
[HtmlTargetElement("a", Attributes = tagHelperAttributeName)]
20+
public class ActiveClassTagHelper : TagHelper
21+
{
22+
private const string tagHelperAttributeName = "our-active-class";
23+
private const string tagHelperAttributeHrefName = "our-active-href";
24+
private const string tagHelperAttributes = tagHelperAttributeName + ", " + tagHelperAttributeHrefName;
25+
26+
private IUmbracoContextAccessor _umbracoContextAccessor;
27+
28+
public ActiveClassTagHelper(IUmbracoContextAccessor umbracoContextAccessor)
29+
{
30+
_umbracoContextAccessor = umbracoContextAccessor;
31+
}
32+
33+
/// <summary>
34+
/// The CSS class name you wish to append to the class attribute
35+
/// on an <a> tag when the page is active/selected
36+
/// </summary>
37+
[HtmlAttributeName(tagHelperAttributeName)]
38+
public string ActiveClassName { get; set; }
39+
40+
41+
/// <summary>
42+
/// If you wish to add an active CSS class on another DOM element than an <a>
43+
/// You can use this attribute to pass a link to the page to check in conjuction with `our-active-class` attribute
44+
/// </summary>
45+
[HtmlAttributeName("our-active-href")]
46+
public string? ActiveLink { get; set; }
47+
48+
public override void Process(TagHelperContext context, TagHelperOutput output)
49+
{
50+
// Remove the attribute
51+
// We don't want it in the markup we send down to the page
52+
output.Attributes.RemoveAll(tagHelperAttributeName);
53+
54+
var ctx = _umbracoContextAccessor.GetRequiredUmbracoContext();
55+
56+
// If we have active link prop set use that othewise try to find the href attribute on an <a> and its value
57+
var href = string.IsNullOrEmpty(ActiveLink) ? output.Attributes["href"]?.Value.ToString() : ActiveLink;
58+
if (string.IsNullOrEmpty(href))
59+
{
60+
return;
61+
}
62+
63+
// Try & parse href as URI, as it could be relative or absolute
64+
// or contain a quersystring we only want the path part
65+
if (Uri.TryCreate(href, UriKind.Absolute, out Uri link) || Uri.TryCreate(ctx.PublishedRequest.Uri, href, out link))
66+
{
67+
// Get the node based of the value in the HREF
68+
var nodeOfLink = ctx.Content.GetByRoute(link.AbsolutePath);
69+
if (nodeOfLink == null)
70+
{
71+
return;
72+
}
73+
74+
// Get the current node of the page that is rendering
75+
var currentPageRendering = ctx.PublishedRequest.PublishedContent;
76+
77+
// Check if thelink we are rendering is current page or an ancestor
78+
if (nodeOfLink.IsAncestorOrSelf(currentPageRendering))
79+
{
80+
// Is active page
81+
output.AddClass(ActiveClassName, HtmlEncoder.Default);
82+
}
83+
}
84+
}
85+
}
86+
}

README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,34 @@ If you want the edit link to open in a new tab, just add the `target="_blank"` a
292292
<our-edit-link target="_blank">Edit</our-edit-link>
293293
```
294294

295+
## `our-active-class`
296+
This is a tag helper attribute that can be applied to `<a>` element in the razor template or partial. It will use the value inside the attribute and append it to the class attribute of the `<a>`.
297+
If the link inside the href attribute can be found by its route as a content node, if so then it will check with the current page being rendered if its the same node or an ancestor.
298+
299+
This allows for the navigation item to still have the class added to it when a child or grandchildren page is the currently page being rendered.
300+
301+
### Simple Example
302+
```cshtml
303+
@foreach (var item in Model.Root().Children)
304+
{
305+
<a href="@item.Url()" class="nav-link" our-active-class="nav-link--active">@item.Name</a>
306+
}
307+
```
308+
309+
Alternatively you can use the `our-active-class` attribute in conjuction with `our-active-href` attribute to apply this to any HTML DOM element on the page.
310+
311+
```cshtml
312+
<ul>
313+
@foreach (var item in Model.Root().Children)
314+
{
315+
<li our-active-href="@item.Url()" our-active-class="selected">
316+
<a href="@item.Url()" class="nav-link" our-active-class="nav-link--active">@item.Name</a>
317+
</li>
318+
}
319+
</ul>
320+
```
321+
322+
295323
## Video 📺
296324
[![How to create ASP.NET TagHelpers for Umbraco](https://user-images.githubusercontent.com/1389894/138666925-15475216-239f-439d-b989-c67995e5df71.png)](https://www.youtube.com/watch?v=3fkDs0NwIE8)
297325

0 commit comments

Comments
 (0)