Skip to content

Commit 46e9c36

Browse files
committed
Breaking change: NavLinkMatch.All matches queries and fragments with an option to override this behavior.
1 parent eda0dd0 commit 46e9c36

File tree

5 files changed

+88
-52
lines changed

5 files changed

+88
-52
lines changed

src/Components/Web/src/Routing/NavLink.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,19 @@ protected virtual bool ShouldMatch(string currentUriAbsolute)
129129
return true;
130130
}
131131

132+
string uriWithoutQueryAndFragment = GetUriIgnoreQueryAndFragment(currentUriAbsolute);
133+
if (Match == NavLinkMatch.All
134+
&& EqualsHrefExactlyOrIfTrailingSlashAdded(uriWithoutQueryAndFragment))
135+
{
136+
return true;
137+
}
138+
132139
return false;
133140
}
134141

142+
private static string GetUriIgnoreQueryAndFragment(string uri) =>
143+
new Uri(uri).GetLeftPart(UriPartial.Path);
144+
135145
private bool EqualsHrefExactlyOrIfTrailingSlashAdded(string currentUriAbsolute)
136146
{
137147
Debug.Assert(_hrefAbsolute != null);

src/Components/test/E2ETest/Tests/RoutingTest.cs

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ public void CanFollowLinkToOtherPageWithQueryString()
299299
var app = Browser.MountTestComponent<TestRouter>();
300300
app.FindElement(By.LinkText("Other with query")).Click();
301301
Browser.Equal("This is another page.", () => app.FindElement(By.Id("test-info")).Text);
302-
AssertHighlightedLinks("Other", "Other with query");
302+
AssertHighlightedLinks("Other", "Other with base-relative URL (matches all)", "Other with query");
303303
}
304304

305305
[Fact]
@@ -310,7 +310,10 @@ public void CanFollowLinkToDefaultPageWithQueryString()
310310
var app = Browser.MountTestComponent<TestRouter>();
311311
app.FindElement(By.LinkText("Default with query")).Click();
312312
Browser.Equal("This is the default page.", () => app.FindElement(By.Id("test-info")).Text);
313-
AssertHighlightedLinks("Default with query");
313+
AssertHighlightedLinks(
314+
"Default (matches all)",
315+
"Default with base-relative URL (matches all)",
316+
"Default with query");
314317
}
315318

316319
[Fact]
@@ -321,7 +324,11 @@ public void CanFollowLinkToDefaultPageWithQueryString_NoTrailingSlash()
321324
var app = Browser.MountTestComponent<TestRouter>();
322325
app.FindElement(By.LinkText("Default with query, no trailing slash")).Click();
323326
Browser.Equal("This is the default page.", () => app.FindElement(By.Id("test-info")).Text);
324-
AssertHighlightedLinks("Default with query, no trailing slash");
327+
AssertHighlightedLinks(
328+
"Default (matches all)",
329+
"Default with base-relative URL (matches all)",
330+
"Default, no trailing slash (matches all)",
331+
"Default with query, no trailing slash");
325332
}
326333

327334
[Fact]
@@ -332,7 +339,7 @@ public void CanFollowLinkToOtherPageWithHash()
332339
var app = Browser.MountTestComponent<TestRouter>();
333340
app.FindElement(By.LinkText("Other with hash")).Click();
334341
Browser.Equal("This is another page.", () => app.FindElement(By.Id("test-info")).Text);
335-
AssertHighlightedLinks("Other", "Other with hash");
342+
AssertHighlightedLinks("Other", "Other with base-relative URL (matches all)", "Other with hash");
336343
}
337344

338345
[Fact]
@@ -343,7 +350,10 @@ public void CanFollowLinkToDefaultPageWithHash()
343350
var app = Browser.MountTestComponent<TestRouter>();
344351
app.FindElement(By.LinkText("Default with hash")).Click();
345352
Browser.Equal("This is the default page.", () => app.FindElement(By.Id("test-info")).Text);
346-
AssertHighlightedLinks("Default with hash");
353+
AssertHighlightedLinks(
354+
"Default (matches all)",
355+
"Default with base-relative URL (matches all)",
356+
"Default with hash");
347357
}
348358

349359
[Fact]
@@ -354,7 +364,11 @@ public void CanFollowLinkToDefaultPageWithHash_NoTrailingSlash()
354364
var app = Browser.MountTestComponent<TestRouter>();
355365
app.FindElement(By.LinkText("Default with hash, no trailing slash")).Click();
356366
Browser.Equal("This is the default page.", () => app.FindElement(By.Id("test-info")).Text);
357-
AssertHighlightedLinks("Default with hash, no trailing slash");
367+
AssertHighlightedLinks(
368+
"Default with hash, no trailing slash",
369+
"Default (matches all)",
370+
"Default with base-relative URL (matches all)",
371+
"Default, no trailing slash (matches all)");
358372
}
359373

360374
[Fact]
@@ -384,31 +398,25 @@ public void CanFollowLinkDefinedInOpenShadowRoot()
384398
}
385399

386400
[Fact]
387-
public void CanOverrideNavLinkToIgnoreFragment()
401+
public void CanOverrideNavLinkToNotIgnoreFragment()
388402
{
389403
SetUrlViaPushState("/layout-overridden/for-hash");
390404

391405
var app = Browser.MountTestComponent<TestRouter>();
392406
app.FindElement(By.LinkText("Override layout with hash, no trailing slash")).Click();
393407
Browser.Equal("This is the page with overridden layout.", () => app.FindElement(By.Id("test-info")).Text);
394-
AssertHighlightedLinks(
395-
"Override layout (matches all)",
396-
"Override layout, no trailing slash (matches all)",
397-
"Override layout with hash, no trailing slash");
408+
AssertHighlightedLinks("Override layout with hash, no trailing slash");
398409
}
399410

400411
[Fact]
401-
public void CanOverrideNavLinkToIgnoreQuery()
412+
public void CanOverrideNavLinkToNotIgnoreQuery()
402413
{
403414
SetUrlViaPushState("/layout-overridden");
404415

405416
var app = Browser.MountTestComponent<TestRouter>();
406417
app.FindElement(By.LinkText("Override layout with query, no trailing slash")).Click();
407418
Browser.Equal("This is the page with overridden layout.", () => app.FindElement(By.Id("test-info")).Text);
408-
AssertHighlightedLinks(
409-
"Override layout (matches all)",
410-
"Override layout, no trailing slash (matches all)",
411-
"Override layout with query, no trailing slash");
419+
AssertHighlightedLinks("Override layout with query, no trailing slash");
412420
}
413421

414422
[Fact]

src/Components/test/testassets/BasicTestApp/RouterTest/LinksOverridden.razor

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
}
77
</style>
88
<ul>
9-
<li><NavLinkIgnoreQueryAndFragmentString href="/subdir/layout-overridden/" Match=NavLinkMatch.All>Override layout (matches all)</NavLinkIgnoreQueryAndFragmentString></li>
10-
<li><NavLinkIgnoreQueryAndFragmentString href="/subdir/layout-overridden" Match=NavLinkMatch.All>Override layout, no trailing slash (matches all)</NavLinkIgnoreQueryAndFragmentString></li>
11-
<li><NavLinkIgnoreQueryAndFragmentString href="/subdir/layout-overridden/?abc=123">Override layout with query</NavLinkIgnoreQueryAndFragmentString></li>
12-
<li><NavLinkIgnoreQueryAndFragmentString href="/subdir/layout-overridden?abc=123">Override layout with query, no trailing slash</NavLinkIgnoreQueryAndFragmentString></li>
13-
<li><NavLinkIgnoreQueryAndFragmentString href="/subdir/layout-overridden/#blah">Override layout with hash</NavLinkIgnoreQueryAndFragmentString></li>
14-
<li><NavLinkIgnoreQueryAndFragmentString href="/subdir/layout-overridden#blah">Override layout with hash, no trailing slash</NavLinkIgnoreQueryAndFragmentString></li>
15-
<li><NavLinkIgnoreQueryAndFragmentString href="/subdir/layout-overridden/Default.html">Override layout with extension</NavLinkIgnoreQueryAndFragmentString></li>
16-
<li><NavLinkIgnoreQueryAndFragmentString href="/subdir/layout-overridden/Other">Override Other</NavLinkIgnoreQueryAndFragmentString></li>
17-
<li><NavLinkIgnoreQueryAndFragmentString href="/subdir/Other" Match=NavLinkMatch.All>Override Other with base-relative URL (matches all)</NavLinkIgnoreQueryAndFragmentString></li>
9+
<li><NavLinkNotIgnoreQueryOrFragmentString href="/subdir/layout-overridden/" Match=NavLinkMatch.All>Override layout (matches all)</NavLinkNotIgnoreQueryOrFragmentString></li>
10+
<li><NavLinkNotIgnoreQueryOrFragmentString href="/subdir/layout-overridden" Match=NavLinkMatch.All>Override layout, no trailing slash (matches all)</NavLinkNotIgnoreQueryOrFragmentString></li>
11+
<li><NavLinkNotIgnoreQueryOrFragmentString href="/subdir/layout-overridden/?abc=123">Override layout with query</NavLinkNotIgnoreQueryOrFragmentString></li>
12+
<li><NavLinkNotIgnoreQueryOrFragmentString href="/subdir/layout-overridden?abc=123">Override layout with query, no trailing slash</NavLinkNotIgnoreQueryOrFragmentString></li>
13+
<li><NavLinkNotIgnoreQueryOrFragmentString href="/subdir/layout-overridden/#blah">Override layout with hash</NavLinkNotIgnoreQueryOrFragmentString></li>
14+
<li><NavLinkNotIgnoreQueryOrFragmentString href="/subdir/layout-overridden#blah">Override layout with hash, no trailing slash</NavLinkNotIgnoreQueryOrFragmentString></li>
15+
<li><NavLinkNotIgnoreQueryOrFragmentString href="/subdir/layout-overridden/Default.html">Override layout with extension</NavLinkNotIgnoreQueryOrFragmentString></li>
16+
<li><NavLinkNotIgnoreQueryOrFragmentString href="/subdir/layout-overridden/Other">Override Other</NavLinkNotIgnoreQueryOrFragmentString></li>
17+
<li><NavLinkNotIgnoreQueryOrFragmentString href="/subdir/Other" Match=NavLinkMatch.All>Override Other with base-relative URL (matches all)</NavLinkNotIgnoreQueryOrFragmentString></li>
1818
</ul>

src/Components/test/testassets/BasicTestApp/RouterTest/NavLinkIgnoreQueryAndFragmentString.razor

Lines changed: 0 additions & 27 deletions
This file was deleted.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Globalization;
5+
using Microsoft.AspNetCore.Components;
6+
using Microsoft.AspNetCore.Components.Routing;
7+
8+
public class NavLinkNotIgnoreQueryOrFragmentString : NavLink
9+
{
10+
string hrefAbsolute;
11+
NavigationManager _navigationManager;
12+
13+
public NavLinkNotIgnoreQueryOrFragmentString(NavigationManager navigationManager)
14+
{
15+
_navigationManager = navigationManager;
16+
}
17+
18+
protected override void OnInitialized()
19+
{
20+
string href = "";
21+
if (AdditionalAttributes != null && AdditionalAttributes.TryGetValue("href", out var obj))
22+
{
23+
href = Convert.ToString(obj, CultureInfo.InvariantCulture) ?? "";
24+
}
25+
hrefAbsolute = _navigationManager.ToAbsoluteUri(href).AbsoluteUri;
26+
base.OnInitialized();
27+
}
28+
protected override bool ShouldMatch(string currentUriAbsolute)
29+
{
30+
bool baseMatch = base.ShouldMatch(currentUriAbsolute);
31+
if (!baseMatch || string.IsNullOrEmpty(hrefAbsolute) || Match != NavLinkMatch.All)
32+
{
33+
return baseMatch;
34+
}
35+
36+
if (NormalizeUri(hrefAbsolute) == NormalizeUri(currentUriAbsolute))
37+
{
38+
return true;
39+
}
40+
return false;
41+
}
42+
43+
private static string NormalizeUri(string uri) =>
44+
uri.EndsWith('/') ? uri.TrimEnd('/') : uri;
45+
}

0 commit comments

Comments
 (0)