Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/Components/Web.JS/src/Services/NavigationEnhancement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

import { synchronizeDomContent } from '../Rendering/DomMerging/DomSync';
import { attachProgrammaticEnhancedNavigationHandler, handleClickForNavigationInterception, hasInteractiveRouter, isForSamePath, isSamePageWithHash, notifyEnhancedNavigationListeners, performScrollToElementOnTheSamePage } from './NavigationUtils';
import { attachProgrammaticEnhancedNavigationHandler, handleClickForNavigationInterception, hasInteractiveRouter, isForSamePath, notifyEnhancedNavigationListeners, performScrollToElementOnTheSamePage, isSamePageWithHash } from './NavigationUtils';
import { resetScrollAfterNextBatch, resetScrollIfNeeded } from '../Rendering/Renderer';

/*
Expand Down Expand Up @@ -99,7 +99,7 @@ function onDocumentClick(event: MouseEvent) {
handleClickForNavigationInterception(event, absoluteInternalHref => {
const originalLocation = location.href;

const shouldScrollToHash = isSamePageWithHash(absoluteInternalHref);
const shouldScrollToHash = isSamePageWithHash(originalLocation, absoluteInternalHref);
history.pushState(null, /* ignored title */ '', absoluteInternalHref);

if (shouldScrollToHash) {
Expand All @@ -120,6 +120,11 @@ function onPopState(state: PopStateEvent) {
return;
}

if (state.state == null && isSamePageWithHash(currentContentUrl, location.href)) {
currentContentUrl = location.href;
return;
}

// load the new page
performEnhancedPageLoad(location.href, /* interceptedLink */ false);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Components/Web.JS/src/Services/NavigationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ function performExternalNavigation(uri: string, replace: boolean) {
async function performInternalNavigation(absoluteInternalHref: string, interceptedLink: boolean, replace: boolean, state: string | undefined = undefined, skipLocationChangingCallback = false) {
ignorePendingNavigation();

if (isSamePageWithHash(absoluteInternalHref)) {
if (isSamePageWithHash(location.href, absoluteInternalHref)) {
saveToBrowserHistory(absoluteInternalHref, replace, state);
performScrollToElementOnTheSamePage(absoluteInternalHref);
return;
Expand Down
8 changes: 5 additions & 3 deletions src/Components/Web.JS/src/Services/NavigationUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ export function isWithinBaseUriSpace(href: string) {
&& (nextChar === '' || nextChar === '/' || nextChar === '?' || nextChar === '#');
}

export function isSamePageWithHash(absoluteHref: string): boolean {
const url = new URL(absoluteHref);
return url.hash !== '' && location.origin === url.origin && location.pathname === url.pathname && location.search === url.search;
export function isSamePageWithHash(oldUrl: string, newUrl: string): boolean {
const a = new URL(oldUrl);
const b = new URL(newUrl);
return a.origin === b.origin && a.pathname === b.pathname
&& a.search === b.search && b.hash !== '';
}

export function isForSamePath(url1: string, url2: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Microsoft.AspNetCore.InternalTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.BiDi.Communication;
using OpenQA.Selenium.DevTools;
using OpenQA.Selenium.Support.Extensions;
using TestServer;
using Xunit.Abstractions;
Expand Down Expand Up @@ -195,6 +196,40 @@ public void CanScrollToHashWithoutPerformingFullNavigation()
.EndsWith("scroll-to-hash", StringComparison.Ordinal));
}

[Fact]
public void NonEnhancedNavCanScrollToHashWithoutFetchingPageAnchor()
{
Navigate($"{ServerPathBase}/nav/scroll-to-hash");
var originalTextElem = Browser.Exists(By.CssSelector("#anchor #text"));
Browser.Equal("Text", () => originalTextElem.Text);

Browser.Exists(By.CssSelector("#anchor #scroll-anchor")).Click();
Browser.True(() => Browser.GetScrollY() > 500);
Browser.True(() => Browser
.Exists(By.CssSelector("#anchor #uri-on-page-load"))
.GetDomAttribute("data-value")
.EndsWith("scroll-to-hash", StringComparison.Ordinal));

Browser.Equal("Text", () => originalTextElem.Text);
}

[Fact]
public void NonEnhancedNavCanScrollToHashWithoutFetchingPageNavLink()
{
Navigate($"{ServerPathBase}/nav/scroll-to-hash");
var originalTextElem = Browser.Exists(By.CssSelector("#navlink #text"));
Browser.Equal("Text", () => originalTextElem.Text);

Browser.Exists(By.CssSelector("#navlink #scroll-anchor")).Click();
Browser.True(() => Browser.GetScrollY() > 500);
Browser.True(() => Browser
.Exists(By.CssSelector("#navlink #uri-on-page-load"))
.GetDomAttribute("data-value")
.EndsWith("scroll-to-hash", StringComparison.Ordinal));

Browser.Equal("Text", () => originalTextElem.Text);
}

[Theory]
[InlineData("server")]
[InlineData("webassembly")]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@page "/nav/scroll-to-hash"
@attribute [StreamRendering]
@inject NavigationManager NavigationManager
@using Microsoft.AspNetCore.Components.Forms

<PageTitle>Page for scrolling to hash</PageTitle>

Expand All @@ -13,6 +14,18 @@
<div id="uri-on-page-load" style="display: none" data-value="@uriOnPageLoad"></div>
</p>

<div data-enhance-nav="false" id="anchor">
<a id="scroll-anchor" href="nav/scroll-to-hash#some-content">Scroll via anchor</a>
<div id="uri-on-page-load" style="display: none" data-value="@uriOnPageLoad"></div>
<p id="text">Text</p>
</div>

<div data-enhance-nav="false" id="navlink">
<NavLink id="scroll-anchor" href="nav/scroll-to-hash#some-content">Scroll via NavLink</NavLink>
<div id="uri-on-page-load" style="display: none" data-value="@uriOnPageLoad"></div>
<p id="text">Text</p>
</div>

<div style="height: 2000px; border: 2px dashed red;">spacer</div>

@if (showContent)
Expand Down
Loading