Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🆕 feat(PageStack): add support for current active tab change event #2217

Merged
merged 2 commits into from
Nov 6, 2024
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
7 changes: 6 additions & 1 deletion docs/Masa.Blazor.Docs/Shared/PageStackLayout.razor
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@

@code {

private string[] _tabbedPatterns = ["/blazor/examples/page-stack/tab*"];
private string[] _tabbedPatterns =
[
"/blazor/examples/page-stack/tab1",
"/blazor/examples/page-stack/tab2",
"/blazor/examples/page-stack/tab3"
];

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class PageStackNavController()
public event EventHandler<PageStackPopEventArgs>? StackPop;

/// <summary>
/// Occurs when a page is replaced by a new page.
/// Occurs when a new page replaces a page.
/// </summary>
public event EventHandler<PageStackReplaceEventArgs>? StackReplace;

Expand All @@ -39,6 +39,11 @@ public class PageStackNavController()
/// </summary>
internal event EventHandler<PageStackGoBackToPageEventArgs>? StackGoBackTo;

/// <summary>
/// Occurs when the active tab is changed.
/// </summary>
public event EventHandler<PageStackTabChangedEventArgs>? TabChanged;

/// <summary>
/// Push a new page onto the page stack.
/// </summary>
Expand Down Expand Up @@ -126,7 +131,7 @@ public void Clear()
}

/// <summary>
/// Clear current page stack and navigate to a tab.
/// Clear the current page stack and navigate to a tab.
/// </summary>
/// <param name="relativeUri"></param>
[Obsolete("Use GoBackToTab instead.")]
Expand All @@ -136,7 +141,7 @@ public void GoToTab(string relativeUri)
}

/// <summary>
/// Clear current page stack and navigate to a tab.
/// Clear the current page stack and navigate to a tab.
/// </summary>
/// <param name="relativeUri"></param>
public void GoBackToTab(string relativeUri)
Expand All @@ -149,6 +154,11 @@ internal void NotifyPageClosed(string relativeUri)
PageClosed?.Invoke(this, new PageStackPageClosedEventArgs(relativeUri));
}

internal void NotifyTabChanged(string currentTabPath, Regex currentTabPattern)
{
TabChanged?.Invoke(this, new PageStackTabChangedEventArgs(currentTabPath, currentTabPattern.IsMatch));
}

private void ExecuteIfTimeElapsed(Action action)
{
var now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Masa.Blazor.Presets.PageStack.NavController;

public class PageStackTabChangedEventArgs(string currentTab, Func<string, bool> isMatch) : EventArgs
{
/// <summary>
/// The absolute path of the current tab.
/// </summary>
public string CurrentTab { get; init; } = currentTab;

/// <summary>
/// Checks whether the given path matches the current tab.
/// </summary>
/// <returns>
/// True if the path matches the current tab; otherwise, false.
/// </returns>
public Func<string, bool> IsMatch { get; init; } = isMatch;
}
38 changes: 30 additions & 8 deletions src/Masa.Blazor/Presets/PageStack/PPageStack.razor.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Masa.Blazor.Presets.PageStack;
using Masa.Blazor.Presets.PageStack.NavController;
using Microsoft.AspNetCore.Components.Routing;

namespace Masa.Blazor.Presets;

Expand All @@ -25,16 +26,18 @@ public partial class PPageStack : PatternPathComponentBase
internal readonly StackPages Pages = new();

/// <summary>
/// Determines whether the popstate event is triggered by user action,
/// Determines whether user action triggers the popstate event,
/// different from the browser's back button.
/// </summary>
private bool _popstateByUserAction;

private string? _lastVisitedTabPath;
private PageType _targetPageType;
private string? _latestTabPath;
private long _lastOnPreviousClickTimestamp;

// just for knowing whether the tab has been changed
private (Regex Pattern, string AbsolutePath) _lastVisitedTab;

private HashSet<string> _prevTabbedPatterns = new();
private HashSet<Regex> _cachedTabbedPatterns = new();

Expand All @@ -54,13 +57,17 @@ protected override void OnInitialized()
{
_lastVisitedTabPath = targetPath;
_targetPageType = PageType.Tab;

_lastVisitedTab = (tabbedPattern, targetPath);
}
else
{
_targetPageType = PageType.Stack;
Push(NavigationManager.Uri);
}

NavigationManager.LocationChanged += NavigationManagerOnLocationChanged;

InternalPageStackNavManager = PageStackNavControllerFactory.Create(Name ?? string.Empty);
InternalPageStackNavManager.StackPush += InternalStackStackNavManagerOnStackPush;
InternalPageStackNavManager.StackPop += InternalPageStackNavManagerOnStackPop;
Expand All @@ -71,6 +78,18 @@ protected override void OnInitialized()
_dotNetObjectReference = DotNetObjectReference.Create(this);
}

private void NavigationManagerOnLocationChanged(object? sender, LocationChangedEventArgs e)
{
var currentPath = NavigationManager.GetAbsolutePath();
var tabbedPattern = _cachedTabbedPatterns.FirstOrDefault(u => u.IsMatch(currentPath));

if (tabbedPattern is not null && _lastVisitedTab.Pattern != tabbedPattern)
{
_lastVisitedTab = (tabbedPattern, currentPath);
InternalPageStackNavManager?.NotifyTabChanged(currentPath, tabbedPattern);
}
}

protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
Expand Down Expand Up @@ -171,7 +190,8 @@ private async void InternalStackStackNavManagerOnStackClear(object? sender, Page
{
await Js.InvokeVoidAsync(JsInteropConstants.HistoryGo, -Pages.Count);

var backToLastVisitTab = string.IsNullOrWhiteSpace(e.RelativeUri) || _lastVisitedTabPath == GetAbsolutePath(e.RelativeUri);
var backToLastVisitTab = string.IsNullOrWhiteSpace(e.RelativeUri) ||
_lastVisitedTabPath == GetAbsolutePath(e.RelativeUri);

if (backToLastVisitTab)
{
Expand Down Expand Up @@ -278,11 +298,7 @@ private void DisableRootScrollbar(bool disable)

protected override async ValueTask DisposeAsyncCore()
{
if (_module is not null)
{
await _module.InvokeVoidAsync("detachListener", _dotnetObjectId);
await _module.DisposeAsync();
}
NavigationManager.LocationChanged -= NavigationManagerOnLocationChanged;

if (InternalPageStackNavManager is not null)
{
Expand All @@ -292,6 +308,12 @@ protected override async ValueTask DisposeAsyncCore()
InternalPageStackNavManager.StackClear -= InternalStackStackNavManagerOnStackClear;
InternalPageStackNavManager.StackGoBackTo -= InternalPageStackNavManagerOnStackGoBackTo;
}

if (_module is not null)
{
await _module.InvokeVoidAsync("detachListener", _dotnetObjectId);
await _module.DisposeAsync();
}
}

private enum PageType
Expand Down
Loading