Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
<Compile Include="$(ComponentsSharedSourceRoot)src\JsonSerializerOptionsProvider.cs" />
<Compile Include="$(ComponentsSharedSourceRoot)src\HotReloadManager.cs" LinkBase="HotReload" />
<Compile Include="$(ComponentsSharedSourceRoot)src\RootTypeCache.cs" LinkBase="Shared" />
<Compile Include="$(ComponentsSharedSourceRoot)src\QueryParameterValueSupplier.cs" LinkBase="Routing" />
<Compile Include="$(ComponentsSharedSourceRoot)src\StringSegmentAccumulator.cs" LinkBase="Routing" />
<Compile Include="$(ComponentsSharedSourceRoot)src\QueryParameterNameComparer.cs" LinkBase="Routing" />
<Compile Include="$(ComponentsSharedSourceRoot)src\UrlValueConstraint.cs" LinkBase="Routing" />
<Compile Include="$(ComponentsSharedSourceRoot)src\Reflection\PropertyGetter.cs" LinkBase="Shared" />
<Compile Include="$(ComponentsSharedSourceRoot)src\Reflection\PropertySetter.cs" LinkBase="Shared" />
<Compile Include="$(SharedSourceRoot)LinkerFlags.cs" LinkBase="Shared" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,30 +74,16 @@ private bool TryUpdateUri()
return false;
}

var query = GetQueryString(navigationManager.Uri);
var query = QueryParameterValueSupplier.GetQueryString(navigationManager.Uri);

if (!query.Span.SequenceEqual(GetQueryString(_lastUri).Span))
if (!query.Span.SequenceEqual(QueryParameterValueSupplier.GetQueryString(_lastUri).Span))
{
_queryChanged = true;
_queryParameterValueSupplier.ReadParametersFromQuery(query);
}

_lastUri = navigationManager.Uri;
return true;

static ReadOnlyMemory<char> GetQueryString(string? url)
{
var queryStartPos = url?.IndexOf('?') ?? -1;

if (queryStartPos < 0)
{
return default;
}

Debug.Assert(url is not null);
var queryEndPos = url.IndexOf('#', queryStartPos);
return url.AsMemory(queryStartPos..(queryEndPos < 0 ? url.Length : queryEndPos));
}
}

private void SubscribeToLocationChanges()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@using Microsoft.AspNetCore.Components.Rendering
@using Microsoft.AspNetCore.Components.Rendering
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@namespace Microsoft.AspNetCore.Components.QuickGrid
Expand All @@ -24,10 +24,26 @@

if (Sortable.HasValue ? Sortable.Value : IsSortableByDefault())
{
<button class="col-title" type="button" @onclick="@(() => Grid.SortByColumnAsync(this))">
<div class="col-title-text">@Title</div>
<div class="sort-indicator" aria-hidden="true"></div>
</button>
@if (QuickGridFeatureFlags.EnableUrlBasedQuickGridNavigationAndSorting && Title is not null)
{
<a class="col-title" href="@(Grid.GetSortUrl(this))">
<div class="col-title-text">@Title</div>
<div class="sort-indicator" aria-hidden="true"></div>
</a>
}
else if (!QuickGridFeatureFlags.EnableUrlBasedQuickGridNavigationAndSorting && Title is not null)
{
<button class="col-title" type="button" @onclick="@(() => Grid.SortByColumnAsync(this))">
<div class="col-title-text">@Title</div>
<div class="sort-indicator" aria-hidden="true"></div>
</button>
}
else
{
<div class="col-title">
<div class="col-title-text">@Title</div>
</div>
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
padding: 0;
}

/* If the column is sortable, its title is rendered as a button element for accessibility and to support navigation by tab */
/* If the column is sortable, its title is rendered as a link element for accessibility and to support navigation by tab */
a.col-title,
button.col-title {
border: none;
background: none;
position: relative;
cursor: pointer;
text-decoration: none;
color: inherit;
}

.col-justify-center .col-title {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<_CurrentProjectDiscoveredScopedCssFiles Include="@(ThemeCssFiles)" RelativePath="%(Identity)" BasePath="_content/$(AssemblyName)" />

<Compile Include="$(ComponentsSharedSourceRoot)src\AttributeUtilities.cs" LinkBase="Infrastructure" />
<Compile Include="$(ComponentsSharedSourceRoot)src\QueryParameterValueSupplier.cs" LinkBase="Infrastructure" />
<Compile Include="$(ComponentsSharedSourceRoot)src\StringSegmentAccumulator.cs" LinkBase="Infrastructure" />
<Compile Include="$(ComponentsSharedSourceRoot)src\QueryParameterNameComparer.cs" LinkBase="Infrastructure" />
<Compile Include="$(ComponentsSharedSourceRoot)src\UrlValueConstraint.cs" LinkBase="Infrastructure" />
<Compile Include="$(SharedSourceRoot)QueryStringEnumerable.cs" LinkBase="Infrastructure" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class PaginationState
/// </summary>
public event EventHandler<int?>? TotalItemCountChanged;

internal string QueryName { get; set; } = "";
Comment thread
dariatiurina marked this conversation as resolved.
internal EventCallbackSubscribable<PaginationState> CurrentPageItemsChanged { get; } = new();
internal EventCallbackSubscribable<PaginationState> TotalItemCountChangedSubscribable { get; } = new();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web
@namespace Microsoft.AspNetCore.Components.QuickGrid

<div class="paginator">
Expand All @@ -15,14 +15,28 @@
}
</div>
<nav role="navigation">
<button class="go-first" type="button" @onclick="GoFirstAsync" disabled="@(!CanGoBack)" title="Go to first page" aria-label="Go to first page"></button>
<button class="go-previous" type="button" @onclick="GoPreviousAsync" disabled="@(!CanGoBack)" title="Go to previous page" aria-label="Go to previous page"></button>
<div class="pagination-text">
Page <strong>@(State.CurrentPageIndex + 1)</strong>
of <strong>@(State.LastPageIndex + 1)</strong>
</div>
<button class="go-next" type="button" @onclick="GoNextAsync" disabled="@(!CanGoForwards)" title="Go to next page" aria-label="Go to next page"></button>
<button class="go-last" type="button" @onclick="GoLastAsync" disabled="@(!CanGoForwards)" title="Go to last page" aria-label="Go to last page"></button>
@if (QuickGridFeatureFlags.EnableUrlBasedQuickGridNavigationAndSorting)
{
<a class="go-first" href="@(CanGoBack ? GetPageUrl(0) : null)" title="Go to first page" aria-label="Go to first page" aria-disabled="@(!CanGoBack ? "true" : "false")">«</a>
<a class="go-previous" href="@(CanGoBack ? GetPageUrl(State.CurrentPageIndex - 1) : null)" title="Go to previous page" aria-label="Go to previous page" aria-disabled="@(!CanGoBack ? "true" : "false")">‹</a>
<div class="pagination-text">
Page <strong>@(State.CurrentPageIndex + 1)</strong>
of <strong>@(State.LastPageIndex + 1)</strong>
</div>
<a class="go-next" href="@(CanGoForwards ? GetPageUrl(State.CurrentPageIndex + 1) : null)" title="Go to next page" aria-label="Go to next page" aria-disabled="@(!CanGoForwards ? "true" : "false")">›</a>
<a class="go-last" href="@(CanGoForwards ? GetPageUrl(State.LastPageIndex.GetValueOrDefault(0)) : null)" title="Go to last page" aria-label="Go to last page" aria-disabled="@(!CanGoForwards ? "true" : "false")">»</a>
}
else
{
<button class="go-first" type="button" @onclick="GoFirstAsync" disabled="@(!CanGoBack)" title="Go to first page" aria-label="Go to first page"></button>
<button class="go-previous" type="button" @onclick="GoPreviousAsync" disabled="@(!CanGoBack)" title="Go to previous page" aria-label="Go to previous page"></button>
<div class="pagination-text">
Page <strong>@(State.CurrentPageIndex + 1)</strong>
of <strong>@(State.LastPageIndex + 1)</strong>
</div>
<button class="go-next" type="button" @onclick="GoNextAsync" disabled="@(!CanGoForwards)" title="Go to next page" aria-label="Go to next page"></button>
<button class="go-last" type="button" @onclick="GoLastAsync" disabled="@(!CanGoForwards)" title="Go to last page" aria-label="Go to last page"></button>
}
</nav>
}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.AspNetCore.Components.QuickGrid.Infrastructure;
using Microsoft.AspNetCore.Components.Routing;

namespace Microsoft.AspNetCore.Components.QuickGrid;

Expand All @@ -12,6 +13,10 @@ public partial class Paginator : IDisposable
{
private readonly EventCallbackSubscriber<PaginationState> _totalItemCountChanged;

[Inject]
private NavigationManager NavigationManager { get; set; } = default!;
private string QueryName => State.QueryName;

/// <summary>
/// Specifies the associated <see cref="PaginationState"/>. This parameter is required.
/// </summary>
Expand All @@ -29,6 +34,15 @@ public Paginator()
{
// The "total item count" handler doesn't need to do anything except cause this component to re-render
_totalItemCountChanged = new(new EventCallback<PaginationState>(this, null));
_queryParameterValueSupplier = new();
}

private readonly QueryParameterValueSupplier _queryParameterValueSupplier;

private string GetPageUrl(int pageIndex)
{
int? pageValue = pageIndex == 0 ? null : pageIndex + 1;
return NavigationManager.GetUriWithQueryParameter(QueryName, pageValue);
}
Comment thread
dariatiurina marked this conversation as resolved.

private Task GoFirstAsync() => GoToPageAsync(0);
Expand All @@ -38,15 +52,68 @@ public Paginator()

private bool CanGoBack => State.CurrentPageIndex > 0;
private bool CanGoForwards => State.CurrentPageIndex < State.LastPageIndex;

private Task GoToPageAsync(int pageIndex)
=> State.SetCurrentPageIndexAsync(pageIndex);

/// <inheritdoc />
protected override void OnParametersSet()
=> _totalItemCountChanged.SubscribeOrMove(State.TotalItemCountChangedSubscribable);
protected override void OnInitialized()
{
if (QuickGridFeatureFlags.EnableUrlBasedQuickGridNavigationAndSorting)
{
NavigationManager.LocationChanged += OnLocationChanged;
}
}

/// <inheritdoc />
protected override Task OnParametersSetAsync()
{
_totalItemCountChanged.SubscribeOrMove(State.TotalItemCountChangedSubscribable);

if (QuickGridFeatureFlags.EnableUrlBasedQuickGridNavigationAndSorting)
{
_queryParameterValueSupplier.ReadParametersFromQuery(QueryParameterValueSupplier.GetQueryString(NavigationManager.Uri));
var pageFromQuery = ReadPageIndexFromQueryString() ?? 0;
if (pageFromQuery != State.CurrentPageIndex)
{
return State.SetCurrentPageIndexAsync(pageFromQuery);
}
}

return Task.CompletedTask;
}

private async void OnLocationChanged(object? sender, LocationChangedEventArgs e)
{
_queryParameterValueSupplier.ReadParametersFromQuery(QueryParameterValueSupplier.GetQueryString(NavigationManager.Uri));
var pageFromQuery = ReadPageIndexFromQueryString() ?? 0;
await InvokeAsync(async () =>
{
if (pageFromQuery != State.CurrentPageIndex)
{
await State.SetCurrentPageIndexAsync(pageFromQuery);
}
StateHasChanged();
});
}

private int? ReadPageIndexFromQueryString()
{
var value = _queryParameterValueSupplier.GetQueryParameterValue(typeof(string), QueryName) as string;
if (value is not null && int.TryParse(value, out var page) && page > 0)
{
return page - 1;
}

return null;
}

/// <inheritdoc />
public void Dispose()
=> _totalItemCountChanged.Dispose();
{
if (QuickGridFeatureFlags.EnableUrlBasedQuickGridNavigationAndSorting)
{
NavigationManager.LocationChanged -= OnLocationChanged;
}
_totalItemCountChanged.Dispose();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,32 @@ nav {
align-items: center;
}

nav a,
nav button {
border: 0;
background: none center center / 1rem no-repeat;
width: 2rem;
height: 2rem;
display: inline-block;
text-decoration: none;
font-size: 0;
cursor: pointer;
padding: 0;
}

nav button[disabled] {
nav a[aria-disabled="true"],
nav button:disabled {
opacity: 0.4;
pointer-events: none;
}

nav button:not([disabled]):hover {
nav a:not([aria-disabled="true"]):hover,
nav button:not(:disabled):hover {
background-color: #eee;
}

nav button:not([disabled]):active {
nav a:not([aria-disabled="true"]):active,
nav button:not(:disabled):active {
background-color: #aaa;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
#nullable enable
Microsoft.AspNetCore.Components.QuickGrid.QuickGrid<TGridItem>.QueryParameterNamePrefix.get -> string!
Microsoft.AspNetCore.Components.QuickGrid.QuickGrid<TGridItem>.QueryParameterNamePrefix.set -> void
Microsoft.AspNetCore.Components.QuickGrid.QuickGrid<TGridItem>.OnRowClick.get -> Microsoft.AspNetCore.Components.EventCallback<TGridItem>
Microsoft.AspNetCore.Components.QuickGrid.QuickGrid<TGridItem>.OnRowClick.set -> void
override Microsoft.AspNetCore.Components.QuickGrid.Paginator.OnInitialized() -> void
override Microsoft.AspNetCore.Components.QuickGrid.Paginator.OnParametersSetAsync() -> System.Threading.Tasks.Task!
override Microsoft.AspNetCore.Components.QuickGrid.QuickGrid<TGridItem>.OnInitialized() -> void
*REMOVED*override Microsoft.AspNetCore.Components.QuickGrid.Paginator.OnParametersSet() -> void
Loading
Loading