2021-03-11 23:26:49 +08:00
#nullable enable
2021-03-12 17:02:11 +08:00
2021-03-11 23:26:49 +08:00
using System ;
using System.Collections.Generic ;
using System.Threading.Tasks ;
using AntDesign.Internal ;
using AntDesign.Locales ;
2020-05-19 17:54:16 +08:00
using Microsoft.AspNetCore.Components ;
2021-03-11 23:26:49 +08:00
using Microsoft.AspNetCore.Components.Rendering ;
using Microsoft.AspNetCore.Components.Web ;
2020-05-19 17:54:16 +08:00
using OneOf ;
2020-05-29 00:33:49 +08:00
namespace AntDesign
2020-05-19 17:54:16 +08:00
{
public partial class Pagination : AntDomComponentBase
{
[Parameter]
2021-03-11 23:26:49 +08:00
public int Total { get ; set ; } = 0 ;
2020-05-19 17:54:16 +08:00
[Parameter]
2021-03-11 23:26:49 +08:00
public int DefaultCurrent { get ; set ; } = InitCurrent ;
2020-05-19 17:54:16 +08:00
[Parameter]
2021-03-11 23:26:49 +08:00
public bool Disabled { get ; set ; } = false ;
2020-06-03 00:22:10 +08:00
[Parameter]
2021-03-11 23:26:49 +08:00
public int Current
{
get = > _current ;
set
{
if ( value = = 0 )
{
return ;
}
if ( value ! = _current )
{
_current = value ;
_currentInputValue = _current ;
}
}
}
2020-05-19 17:54:16 +08:00
[Parameter]
2021-03-11 23:26:49 +08:00
public int DefaultPageSize { get ; set ; } = InitPageSize ;
2020-05-19 17:54:16 +08:00
[Parameter]
2021-03-11 23:26:49 +08:00
public int PageSize
{
get = > _pageSize ;
set
{
if ( value = = 0 )
{
return ;
}
if ( value ! = _pageSize )
{
var current = _current ;
var newCurrent = CalculatePage ( value , _pageSize , Total ) ;
current = current > newCurrent ? newCurrent : current ;
_current = current ;
_currentInputValue = current ;
_pageSize = value ;
}
}
}
[Parameter]
public EventCallback < PaginationEventArgs > OnChange { get ; set ; }
[Parameter]
public bool HideOnSinglePage { get ; set ; } = false ;
[Parameter]
2021-04-09 14:17:20 +08:00
public bool ShowSizeChanger
{
get = > GetShowSizeChanger ( ) ;
set
{
_showSizeChanger = value ;
}
}
2021-03-11 23:26:49 +08:00
[Parameter]
public int [ ] PageSizeOptions { get ; set ; } = PaginationOptions . DefaultPageSizeOptions ;
[Parameter]
public EventCallback < PaginationEventArgs > OnShowSizeChange { get ; set ; }
2020-05-19 17:54:16 +08:00
[Parameter]
2021-03-11 23:26:49 +08:00
public bool ShowQuickJumper { get ; set ; } = false ;
[Parameter]
public RenderFragment ? GoButton { get ; set ; }
[Parameter]
public bool ShowTitle { get ; set ; } = true ;
[Parameter]
public OneOf < Func < PaginationTotalContext , string > , RenderFragment < PaginationTotalContext > > ? ShowTotal { get ; set ; }
2020-05-19 17:54:16 +08:00
[Parameter]
public string Size { get ; set ; } = "default" ;
[Parameter]
2021-03-11 23:26:49 +08:00
public bool Responsive { get ; set ; } = true ;
2020-05-19 17:54:16 +08:00
2021-03-11 23:26:49 +08:00
[Parameter]
public bool Simple { get ; set ; } = false ;
2020-05-19 17:54:16 +08:00
[Parameter]
2021-03-11 23:26:49 +08:00
public PaginationLocale Locale { get ; set ; } = LocaleProvider . CurrentLocale . Pagination ;
2020-05-19 17:54:16 +08:00
[Parameter]
2021-03-11 23:26:49 +08:00
public RenderFragment < PaginationItemRenderContext > ? ItemRender { get ; set ; } = context = > context . OriginalElement ( context ) ;
2020-05-19 17:54:16 +08:00
[Parameter]
2021-03-11 23:26:49 +08:00
public bool ShowLessItems { get ; set ; } = false ;
2020-05-19 17:54:16 +08:00
[Parameter]
2021-03-11 23:26:49 +08:00
public bool ShowPrevNextJumpers { get ; set ; } = true ;
2020-05-19 17:54:16 +08:00
[Parameter]
2021-03-11 23:26:49 +08:00
public string Direction { get ; set ; } = "ltr" ;
2020-05-19 17:54:16 +08:00
[Parameter]
2021-03-11 23:26:49 +08:00
public RenderFragment < PaginationItemRenderContext > ? PrevIcon { get ; set ; }
2020-05-19 17:54:16 +08:00
[Parameter]
2021-03-11 23:26:49 +08:00
public RenderFragment < PaginationItemRenderContext > ? NextIcon { get ; set ; }
2020-05-19 17:54:16 +08:00
[Parameter]
2021-03-11 23:26:49 +08:00
public RenderFragment < PaginationItemRenderContext > ? JumpPrevIcon { get ; set ; }
2020-05-19 17:54:16 +08:00
[Parameter]
2021-03-11 23:26:49 +08:00
public RenderFragment < PaginationItemRenderContext > ? JumpNextIcon { get ; set ; }
2021-04-09 14:17:20 +08:00
[Parameter]
public int TotalBoundaryShowSizeChanger { get ; set ; } = 50 ;
2021-03-11 23:26:49 +08:00
[Parameter(CaptureUnmatchedValues = true)]
public Dictionary < string , object > ? UnmatchedAttributes { get ; set ; }
private const string PrefixCls = "ant-pagination" ;
private ClassMapper _prevClass = new ( ) ;
2020-05-19 17:54:16 +08:00
2021-03-11 23:26:49 +08:00
private ClassMapper _nextClass = new ( ) ;
2020-05-19 17:54:16 +08:00
2021-03-11 23:26:49 +08:00
private ClassMapper _jumpPrevClass = new ( ) ;
private ClassMapper _jumpNextClass = new ( ) ;
private int _current = InitCurrent ;
private int _pageSize = InitPageSize ;
private const int InitCurrent = 1 ;
private const int InitPageSize = 10 ;
private int _currentInputValue ;
private bool IsSmall = > ! Simple & & Size = = "small" ;
2021-04-09 14:17:20 +08:00
private bool? _showSizeChanger ;
2021-03-11 23:26:49 +08:00
protected override void OnInitialized ( )
{
SetClass ( ) ;
SetIcon ( ) ;
var hasOnChange = OnChange . HasDelegate ;
var hasCurrent = _current ! = 0 ;
if ( hasCurrent & & ! hasOnChange )
{
Console . WriteLine ( "Warning: You provided a `current` prop to a Pagination component without an `onChange` handler. This will render a read-only component." ) ;
}
var current = DefaultCurrent ;
if ( Current ! = 0 )
{
current = Current ;
}
2020-05-19 17:54:16 +08:00
2021-03-11 23:26:49 +08:00
var pageSize = DefaultPageSize ;
if ( PageSize ! = 0 )
{
pageSize = PageSize ;
}
2020-09-07 22:46:50 +08:00
2021-03-11 23:26:49 +08:00
current = Math . Min ( current , CalculatePage ( pageSize , PageSize , Total ) ) ;
2020-05-19 17:54:16 +08:00
2021-03-11 23:26:49 +08:00
Current = current ;
_currentInputValue = current ;
PageSize = pageSize ;
2020-05-19 17:54:16 +08:00
2021-03-11 23:26:49 +08:00
base . OnInitialized ( ) ;
}
2020-05-19 17:54:16 +08:00
private void SetClass ( )
{
ClassMapper
2021-03-11 23:26:49 +08:00
. Add ( PrefixCls )
. If ( $"{PrefixCls}-simple" , ( ) = > Simple )
. If ( $"{PrefixCls}-disabled" , ( ) = > Disabled )
2021-03-12 17:02:11 +08:00
. If ( "mini" , ( ) = > ! Simple & & Size = = "small" )
. If ( $"{PrefixCls}-rtl" , ( ) = > RTL ) ;
2021-03-11 23:26:49 +08:00
_prevClass
. Add ( $"{PrefixCls}-prev" )
. If ( $"{PrefixCls}-disabled" , ( ) = > ! HasPrev ( ) ) ;
2021-03-12 17:02:11 +08:00
2021-03-11 23:26:49 +08:00
_nextClass
. Add ( $"{PrefixCls}-next" )
. If ( $"{PrefixCls}-disabled" , ( ) = > ! HasNext ( ) ) ;
2021-03-12 17:02:11 +08:00
2021-03-11 23:26:49 +08:00
_jumpPrevClass
. Add ( $"{PrefixCls}-jump-prev" )
. If ( $"{PrefixCls}-jump-prev-custom-icon" , ( ) = > JumpPrevIcon ! = null ) ;
2021-03-12 17:02:11 +08:00
2021-03-11 23:26:49 +08:00
_jumpNextClass
. Add ( $"{PrefixCls}-jump-next" )
. If ( $"{PrefixCls}-jump-next-custom-icon" , ( ) = > JumpNextIcon ! = null ) ;
2020-05-19 17:54:16 +08:00
}
2021-03-11 23:26:49 +08:00
private int CalculatePage ( int? p , int pageSize , int total )
2020-05-19 17:54:16 +08:00
{
2021-03-11 23:26:49 +08:00
var size = p ? ? pageSize ;
return ( int ) Math . Floor ( ( double ) ( total - 1 ) / size ) + 1 ;
2020-05-19 17:54:16 +08:00
}
2021-03-11 23:26:49 +08:00
private int GetJumpPrevPage ( )
2020-06-03 00:22:10 +08:00
{
2021-03-11 23:26:49 +08:00
return Math . Max ( 1 , _current - ( ShowLessItems ? 3 : 5 ) ) ;
2020-06-03 00:22:10 +08:00
}
2021-03-11 23:26:49 +08:00
private int GetJumpNextPage ( )
2020-05-19 17:54:16 +08:00
{
2021-03-11 23:26:49 +08:00
return Math . Min ( CalculatePage ( null , _pageSize , Total ) , _current + ( ShowLessItems ? 3 : 5 ) ) ;
}
private int GetValidValue ( string inputValue )
{
var allPages = CalculatePage ( null , _pageSize , Total ) ;
var currentInputValue = _currentInputValue ;
int value ;
if ( string . IsNullOrWhiteSpace ( inputValue ) )
2020-05-19 17:54:16 +08:00
{
2021-03-11 23:26:49 +08:00
value = default ;
2020-05-19 17:54:16 +08:00
}
2021-03-11 23:26:49 +08:00
else if ( int . TryParse ( inputValue , out var inputNumber ) )
2020-05-19 17:54:16 +08:00
{
2021-03-11 23:26:49 +08:00
value = inputNumber > = allPages ? allPages : inputNumber ;
2020-05-19 17:54:16 +08:00
}
else
{
2021-03-11 23:26:49 +08:00
value = currentInputValue ;
2020-05-19 17:54:16 +08:00
}
2021-03-11 23:26:49 +08:00
return value ;
2020-05-19 17:54:16 +08:00
}
2021-03-11 23:26:49 +08:00
private bool IsValid ( int page ) = > page ! = _current ;
private bool ShouldDisplayQuickJumper ( ) = > ShowQuickJumper & & Total > _pageSize ;
private void HandleKeyUp ( EventArgs e )
2020-05-19 17:54:16 +08:00
{
2021-03-11 23:26:49 +08:00
if ( e is KeyboardEventArgs ke )
2020-05-19 17:54:16 +08:00
{
2021-03-11 23:26:49 +08:00
var value = GetValidValue ( ke . Key ) ;
_currentInputValue = value ;
if ( ke . Key = = "Enter" )
{
HandleChange ( value ) ;
}
else if ( ke . Key = = "ArrowUp" )
2020-06-03 00:22:10 +08:00
{
2021-03-11 23:26:49 +08:00
HandleChange ( value - 1 ) ;
}
else if ( ke . Key = = "ArrowDown" )
{
HandleChange ( value + 1 ) ;
}
2020-05-19 17:54:16 +08:00
}
}
2021-03-11 23:26:49 +08:00
private async Task ChangePageSize ( int size )
2020-05-19 17:54:16 +08:00
{
2021-03-11 23:26:49 +08:00
var current = _current ;
var newCurrent = CalculatePage ( size , _pageSize , Total ) ;
current = current > newCurrent ? newCurrent : current ;
// fix the issue:
// Once 'total' is 0, 'current' in 'onShowSizeChange' is 0, which is not correct.
if ( newCurrent = = 0 )
2020-05-19 17:54:16 +08:00
{
2021-03-11 23:26:49 +08:00
current = _current ;
2020-06-03 00:22:10 +08:00
}
2021-03-11 23:26:49 +08:00
PageSize = size ;
Current = current ;
if ( OnShowSizeChange . HasDelegate )
{
await OnShowSizeChange . InvokeAsync ( new ( current , size ) ) ;
}
if ( OnChange . HasDelegate )
{
await OnChange . InvokeAsync ( new ( current , size ) ) ;
}
}
private async void HandleChange ( int p )
{
var disabled = Disabled ;
var page = p ;
if ( IsValid ( page ) & & ! disabled )
2020-06-03 00:22:10 +08:00
{
2021-03-11 23:26:49 +08:00
var currentPage = CalculatePage ( null , _pageSize , Total ) ;
if ( page > currentPage )
2020-06-03 00:22:10 +08:00
{
2021-03-11 23:26:49 +08:00
page = currentPage ;
}
else if ( page < 1 )
{
page = 1 ;
}
Current = page ;
var pageSize = _pageSize ;
if ( OnChange . HasDelegate )
{
await OnChange . InvokeAsync ( new ( page , pageSize ) ) ;
}
2020-05-19 17:54:16 +08:00
}
}
2021-03-11 23:26:49 +08:00
private void Prev ( )
2020-05-19 17:54:16 +08:00
{
2021-03-11 23:26:49 +08:00
if ( HasPrev ( ) )
2020-05-19 17:54:16 +08:00
{
2021-03-11 23:26:49 +08:00
HandleChange ( _current - 1 ) ;
2020-05-19 17:54:16 +08:00
}
}
2021-03-11 23:26:49 +08:00
private void Next ( )
2020-05-19 17:54:16 +08:00
{
2021-03-11 23:26:49 +08:00
if ( HasNext ( ) )
{
HandleChange ( _current + 1 ) ;
}
2020-05-19 17:54:16 +08:00
}
2021-03-11 23:26:49 +08:00
private void JumpPrev ( ) = > HandleChange ( GetJumpPrevPage ( ) ) ;
2020-05-19 17:54:16 +08:00
2021-03-11 23:26:49 +08:00
private void JumpNext ( ) = > HandleChange ( GetJumpNextPage ( ) ) ;
2020-05-19 17:54:16 +08:00
2021-03-11 23:26:49 +08:00
private bool HasPrev ( ) = > _current > 1 ;
private bool HasNext ( ) = > _current < CalculatePage ( null , _pageSize , Total ) ;
2021-04-09 14:17:20 +08:00
private bool GetShowSizeChanger ( )
{
if ( _showSizeChanger . HasValue )
{
return _showSizeChanger . Value ;
}
return Total > TotalBoundaryShowSizeChanger ;
}
2021-03-11 23:26:49 +08:00
private void RunIfEnter ( KeyboardEventArgs @event , Action callback )
{
if ( @event . Code = = "Enter" )
{
callback ( ) ;
}
}
private void RunIfEnterPrev ( KeyboardEventArgs e ) = > this . RunIfEnter ( e , Prev ) ;
private void RunIfEnterNext ( KeyboardEventArgs e ) = > this . RunIfEnter ( e , Next ) ;
private void RunIfEnterJumpPrev ( KeyboardEventArgs e ) = > this . RunIfEnter ( e , JumpPrev ) ;
private void RunIfEnterJumpNext ( KeyboardEventArgs e ) = > this . RunIfEnter ( e , JumpNext ) ;
private void HandleGoTO ( EventArgs e )
{
if ( e is KeyboardEventArgs ke & & ke . Key = = "Enter" | | e is MouseEventArgs me & & me . Type = = "click" )
{
HandleChange ( _currentInputValue ) ;
}
}
private RenderFragment RenderPrev ( int prevPage )
{
var disabled = ! this . HasPrev ( ) ;
var prevButton = ItemRender . Invoke ( new ( prevPage , PaginationItemType . Prev , GetItemIcon ( PrevIcon , "prev page" ) , disabled ) ) ;
2020-05-19 17:54:16 +08:00
2021-03-11 23:26:49 +08:00
return prevButton ;
}
2020-05-19 17:54:16 +08:00
2021-03-11 23:26:49 +08:00
private RenderFragment RenderNext ( int nextPage )
{
var disabled = ! this . HasNext ( ) ;
var nextButton = ItemRender . Invoke ( new ( nextPage , PaginationItemType . Next , GetItemIcon ( NextIcon , "next page" ) , disabled ) ) ;
return nextButton ;
}
2020-05-19 17:54:16 +08:00
}
}