Skip to content

Commit

Permalink
Added PageNumberTemplate and capabilities in DataPager control
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasherceg committed Jul 12, 2024
1 parent 8c433d6 commit 67b4d47
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 16 deletions.
106 changes: 90 additions & 16 deletions src/Framework/Framework/Controls/DataPager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,20 @@ public ITemplate? NextPageTemplate
public static readonly DotvvmProperty NextPageTemplateProperty =
DotvvmProperty.Register<ITemplate?, DataPager>(c => c.NextPageTemplate, null);

/// <summary>
/// Gets or sets the template of the button which moves the user to the numbered page.
/// </summary>
[MarkupOptions(AllowBinding = false, MappingMode = MappingMode.InnerElement)]
[ConstantDataContextChange(typeof(int[]), order: 0)]
[CollectionElementDataContextChange(order: 1)]
public ITemplate? PageNumberTemplate
{
get { return (ITemplate?)GetValue(PageNumberTemplateProperty); }
set { SetValue(PageNumberTemplateProperty, value); }
}
public static readonly DotvvmProperty PageNumberTemplateProperty =
DotvvmProperty.Register<ITemplate?, DataPager>(c => c.PageNumberTemplate, null);

/// <summary>
/// Gets or sets whether a hyperlink should be rendered for the current page number. If set to false, only a plain text is rendered.
/// </summary>
Expand Down Expand Up @@ -126,6 +140,27 @@ public bool Enabled
public static readonly DotvvmProperty EnabledProperty =
DotvvmPropertyWithFallback.Register<bool, DataPager>(nameof(Enabled), FormControls.EnabledProperty);

/// <summary>
/// Gets or sets styles for the list item element (&lt;li&gt;) rendered by the component.
/// </summary>
public HtmlCapability ListItemHtmlCapability
{
get => (HtmlCapability)ListItemHtmlCapabilityProperty.GetValue(this);
set => ListItemHtmlCapabilityProperty.SetValue(this, value);
}
public static readonly DotvvmCapabilityProperty ListItemHtmlCapabilityProperty = DotvvmCapabilityProperty.RegisterCapability<HtmlCapability, DataPager>("ListItem");

/// <summary>
/// Gets or sets styles for the link buttons rendered by the component.
/// </summary>
public HtmlCapability LinkHtmlCapability
{
get => (HtmlCapability)LinkHtmlCapabilityProperty.GetValue(this);
set => LinkHtmlCapabilityProperty.SetValue(this, value);
}
public static readonly DotvvmCapabilityProperty LinkHtmlCapabilityProperty = DotvvmCapabilityProperty.RegisterCapability<HtmlCapability, DataPager>("Link");


/// <summary>
/// Gets or sets the (static) command that will be triggered when the DataPager needs to load data (when navigating to different page).
/// The command accepts one argument of type <see cref="GridViewDataSetOptions{TFilteringOptions, TSortingOptions, TPagingOptions}" /> and should return a new <see cref="GridViewDataSet{T}" /> or <see cref="GridViewDataSetResult{TItem, TFilteringOptions, TSortingOptions, TPagingOptions}" />.
Expand All @@ -138,14 +173,36 @@ public ICommandBinding? LoadData
public static readonly DotvvmProperty LoadDataProperty =
DotvvmProperty.Register<ICommandBinding?, DataPager>(nameof(LoadData));

/// <summary>
/// Gets or sets the CSS class to be applied to the currently active page number.
/// </summary>
[MarkupOptions(AllowBinding = false)]
public string ActiveItemCssClass
{
get { return (string)GetValue(ActiveItemCssClassProperty); }

Check failure on line 182 in src/Framework/Framework/Controls/DataPager.cs

View workflow job for this annotation

GitHub Actions / Build published projects without warnings (Debug)

Converting null literal or possible null value to non-nullable type.

Check failure on line 182 in src/Framework/Framework/Controls/DataPager.cs

View workflow job for this annotation

GitHub Actions / Build published projects without warnings (Debug)

Possible null reference return.

Check failure on line 182 in src/Framework/Framework/Controls/DataPager.cs

View workflow job for this annotation

GitHub Actions / Build published projects without warnings (Debug)

Converting null literal or possible null value to non-nullable type.

Check failure on line 182 in src/Framework/Framework/Controls/DataPager.cs

View workflow job for this annotation

GitHub Actions / Build published projects without warnings (Debug)

Possible null reference return.

Check failure on line 182 in src/Framework/Framework/Controls/DataPager.cs

View workflow job for this annotation

GitHub Actions / Build published projects without warnings (Release)

Converting null literal or possible null value to non-nullable type.

Check failure on line 182 in src/Framework/Framework/Controls/DataPager.cs

View workflow job for this annotation

GitHub Actions / Build published projects without warnings (Release)

Possible null reference return.

Check failure on line 182 in src/Framework/Framework/Controls/DataPager.cs

View workflow job for this annotation

GitHub Actions / Build published projects without warnings (Release)

Converting null literal or possible null value to non-nullable type.

Check failure on line 182 in src/Framework/Framework/Controls/DataPager.cs

View workflow job for this annotation

GitHub Actions / Build published projects without warnings (Release)

Possible null reference return.
set { SetValue(ActiveItemCssClassProperty, value); }
}
public static readonly DotvvmProperty ActiveItemCssClassProperty
= DotvvmProperty.Register<string, DataPager>(c => c.ActiveItemCssClass, "active");

/// <summary>
/// Gets or sets the CSS class that to be applied to the disabled items.
/// </summary>
[MarkupOptions(AllowBinding = false)]
public string DisabledItemCssClass
{
get { return (string)GetValue(DisabledItemCssClassProperty); }

Check failure on line 194 in src/Framework/Framework/Controls/DataPager.cs

View workflow job for this annotation

GitHub Actions / Build published projects without warnings (Debug)

Converting null literal or possible null value to non-nullable type.

Check failure on line 194 in src/Framework/Framework/Controls/DataPager.cs

View workflow job for this annotation

GitHub Actions / Build published projects without warnings (Debug)

Possible null reference return.

Check failure on line 194 in src/Framework/Framework/Controls/DataPager.cs

View workflow job for this annotation

GitHub Actions / Build published projects without warnings (Debug)

Converting null literal or possible null value to non-nullable type.

Check failure on line 194 in src/Framework/Framework/Controls/DataPager.cs

View workflow job for this annotation

GitHub Actions / Build published projects without warnings (Debug)

Possible null reference return.

Check failure on line 194 in src/Framework/Framework/Controls/DataPager.cs

View workflow job for this annotation

GitHub Actions / Build published projects without warnings (Release)

Converting null literal or possible null value to non-nullable type.

Check failure on line 194 in src/Framework/Framework/Controls/DataPager.cs

View workflow job for this annotation

GitHub Actions / Build published projects without warnings (Release)

Possible null reference return.

Check failure on line 194 in src/Framework/Framework/Controls/DataPager.cs

View workflow job for this annotation

GitHub Actions / Build published projects without warnings (Release)

Converting null literal or possible null value to non-nullable type.

Check failure on line 194 in src/Framework/Framework/Controls/DataPager.cs

View workflow job for this annotation

GitHub Actions / Build published projects without warnings (Release)

Possible null reference return.
set { SetValue(DisabledItemCssClassProperty, value); }
}
public static readonly DotvvmProperty DisabledItemCssClassProperty
= DotvvmProperty.Register<string, DataPager>(c => c.DisabledItemCssClass, "disabled");

protected HtmlGenericControl? ContentWrapper { get; set; }
protected HtmlGenericControl? GoToFirstPageButton { get; set; }
protected HtmlGenericControl? GoToPreviousPageButton { get; set; }
protected Repeater? NumberButtonsRepeater { get; set; }
protected HtmlGenericControl? GoToNextPageButton { get; set; }
protected HtmlGenericControl? GoToLastPageButton { get; set; }
protected virtual string ActiveItemCssClass => "active";
protected virtual string DisabledItemCssClass => "disabled";

protected internal override void OnLoad(IDotvvmRequestContext context)
{
Expand Down Expand Up @@ -196,7 +253,7 @@ protected virtual void DataBind(Hosting.IDotvvmRequestContext context)
if (pagerBindings.PageNumbers is {})
{
// number fields
var liTemplate = CreatePageNumberButton(globalEnabled, pagerBindings, context);
var liTemplate = CreatePageNumberButton(globalEnabled, PageNumberTemplate, pagerBindings, context);
AddItemCssClass(liTemplate, context);

NumberButtonsRepeater = new Repeater() {
Expand Down Expand Up @@ -250,22 +307,23 @@ protected virtual HtmlGenericControl CreateWrapperList()

protected override void AddVisibleAttributeOrBinding(in RenderState r, IHtmlWriter writer) { } // handled by the wrapper list

protected virtual HtmlGenericControl CreatePageNumberButton(ValueOrBinding<bool> globalEnabled, DataPagerBindings pagerBindings, IDotvvmRequestContext context)
protected virtual HtmlGenericControl CreatePageNumberButton(ValueOrBinding<bool> globalEnabled, ITemplate? userDefinedContentTemplate, DataPagerBindings pagerBindings, IDotvvmRequestContext context)
{
var liTemplate = new HtmlGenericControl("li");
var liTemplate = new HtmlGenericControl("li", ListItemHtmlCapability);
liTemplate.CssClasses.Add(ActiveItemCssClass, new ValueOrBinding<bool>(pagerBindings.NotNull().IsActivePage.NotNull()));
var link = new LinkButton();

var link = new LinkButton().SetCapability(LinkHtmlCapability);

link.SetBinding(ButtonBase.ClickProperty, pagerBindings.NotNull().GoToPage.NotNull());
SetPageNumberButtonContent(link, pagerBindings, context);
SetPageNumberButtonContent(context, link, pagerBindings, userDefinedContentTemplate);
if (!RenderLinkForCurrentPage) link.SetBinding(IncludeInPageProperty, pagerBindings.IsActivePage.NotNull().Negate());
if (!true.Equals(globalEnabled)) link.SetValue(ButtonBase.EnabledProperty, globalEnabled);
liTemplate.Children.Add(link);

if (!RenderLinkForCurrentPage)
{
var notLink = new Literal();
SetPageNumberSpanContent(notLink, pagerBindings, context);
notLink.RenderSpanElement = true;
var notLink = new HtmlGenericControl("span").SetCapability(LinkHtmlCapability);
SetPageNumberSpanContent(context, notLink, pagerBindings, userDefinedContentTemplate);
notLink.SetBinding(IncludeInPageProperty, pagerBindings.IsActivePage);
liTemplate.Children.Add(notLink);
}
Expand All @@ -274,8 +332,10 @@ protected virtual HtmlGenericControl CreatePageNumberButton(ValueOrBinding<bool>

protected virtual HtmlGenericControl CreateNavigationButton(string defaultText, ITemplate? userDefinedContentTemplate, object enabledValue, ICommandBinding clickCommandBindingExpression,IDotvvmRequestContext context)
{
var li = new HtmlGenericControl("li");
var link = new LinkButton();
var li = new HtmlGenericControl("li", ListItemHtmlCapability);

var link = new LinkButton().SetCapability(LinkHtmlCapability);

SetNavigationButtonContent(context, link, defaultText, userDefinedContentTemplate);
link.SetBinding(ButtonBase.ClickProperty, clickCommandBindingExpression);
if (!true.Equals(enabledValue)) link.SetValue(ButtonBase.EnabledProperty, enabledValue);
Expand All @@ -295,14 +355,28 @@ protected virtual void SetNavigationButtonContent(IDotvvmRequestContext context,
}
}

protected virtual void SetPageNumberSpanContent(Literal notLink, DataPagerBindings pagerBindings, IDotvvmRequestContext context)
protected virtual void SetPageNumberSpanContent(IDotvvmRequestContext context, HtmlGenericControl span, DataPagerBindings pagerBindings, ITemplate? userDefinedContentTemplate)
{
notLink.SetBinding(Literal.TextProperty, pagerBindings.PageNumberText.NotNull());
if (userDefinedContentTemplate != null)
{
userDefinedContentTemplate.BuildContent(context, span);
}
else
{
span.SetBinding(Literal.TextProperty, pagerBindings.PageNumberText.NotNull());
}
}

protected virtual void SetPageNumberButtonContent(LinkButton link, DataPagerBindings pagerBindings, IDotvvmRequestContext context)
protected virtual void SetPageNumberButtonContent(IDotvvmRequestContext context, LinkButton link, DataPagerBindings pagerBindings, ITemplate? userDefinedContentTemplate)
{
link.SetBinding(ButtonBase.TextProperty, pagerBindings.PageNumberText.NotNull());
if (userDefinedContentTemplate != null)
{
userDefinedContentTemplate.BuildContent(context, link);
}
else
{
link.SetBinding(ButtonBase.TextProperty, pagerBindings.PageNumberText.NotNull());
}
}

protected virtual void AddItemCssClass(HtmlGenericControl item, IDotvvmRequestContext context)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using DotVVM.Framework.Controls;
using DotVVM.Framework.ViewModel;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace DotVVM.Samples.BasicSamples.ViewModels.ControlSamples.DataPager
{
public class DataPagerTemplatesViewModel : DotvvmViewModelBase
{
public GridViewDataSet<Data> DataSet { get; set; }

public string[] RomanNumerals { get; set; } = new[] { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX" };

public override Task Init()
{
DataSet = new GridViewDataSet<Data>()
{
PagingOptions = new PagingOptions()
{
PageSize = 3
}
};
return base.Init();
}

public override Task PreRender()
{
if (DataSet.IsRefreshRequired)
{
DataSet.LoadFromQueryable(FakeDB(50));
}

return base.PreRender();
}

private IQueryable<Data> FakeDB(int itemsCreatorCounter)
{
var dbdata = new List<Data>();
for (var i = 0; i < itemsCreatorCounter; i++)
{
dbdata.Add(new Data
{
Text = $"Item {i}"
});
}
return dbdata.AsQueryable();
}

public class Data
{
public string Text { get; set; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public class DataPagerViewModel : DotvvmViewModelBase
{
public GridViewDataSet<Data> DataSet { get; set; }

public string[] RomanNumerals { get; set; } = new[] { "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX" };

public bool Enabled { get; set; } = true;

public int ItemsInDatabaseCount { get; set; } = 2;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
@viewModel DotVVM.Samples.BasicSamples.ViewModels.ControlSamples.DataPager.DataPagerTemplatesViewModel, DotVVM.Samples.Common

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<style>
.pagination {
list-style-type: none;
display: flex;
align-items: center;
}
.page-item {
margin: 0 1em;
}
.page-link {
text-decoration: none;
}
.disabled {
opacity: 0.3;
}
</style>
</head>
<body>

<h1>Templates in DataPager</h1>

<dot:Repeater DataSource="{value: DataSet}" WrapperTagName="ul">
<ItemTemplate>
<li>{{value: Text}}</li>
</ItemTemplate>
</dot:Repeater>

<dot:DataPager DataSet="{value: DataSet}"
class="pagination"
ListItemclass="page-item"
Linkclass="page-link">
<FirstPageTemplate>◀️◀️</FirstPageTemplate>
<PreviousPageTemplate>◀️</PreviousPageTemplate>
<NextPageTemplate>▶️</NextPageTemplate>
<LastPageTemplate>▶️▶️</LastPageTemplate>
<PageNumberTemplate>
{{value: _root.RomanNumerals[_this]}}
</PageNumberTemplate>
</dot:DataPager>

</body>
</html>


Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions src/Samples/Tests/Tests/Control/DataPagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -295,5 +295,27 @@ IElementWrapper GetPageIndex(int index)
CheckNearPageIndexes(Enumerable.Range(11, 7));
});
}

[Fact]
public void Control_DataPager_DataPagerTemplates()
{
RunInAllBrowsers(browser => {
browser.NavigateToUrl(SamplesRouteUrls.ControlSamples_DataPager_DataPagerTemplates);
var pager = browser.Single(".pagination");
var items = pager.FindElements(".page-item");
items.ThrowIfDifferentCountThan(10);
var content = new[] { "◀️◀️", "◀️", "I", "II", "III", "IV", "V", "VI", "▶️", "▶️▶️" };
for (var i = 0; i < items.Count; i++)
{
var item = items[i];
var link = item.Single(".page-link");
AssertUI.TextEquals(link, content[i]);
}
});
}
}
}

0 comments on commit 67b4d47

Please sign in to comment.