Skip to content

Commit eaf640e

Browse files
committed
Added PageNumberTemplate and capabilities in DataPager control
1 parent 3f9b5fc commit eaf640e

6 files changed

Lines changed: 222 additions & 16 deletions

File tree

src/Framework/Framework/Controls/DataPager.cs

Lines changed: 90 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,20 @@ public ITemplate? NextPageTemplate
9393
public static readonly DotvvmProperty NextPageTemplateProperty =
9494
DotvvmProperty.Register<ITemplate?, DataPager>(c => c.NextPageTemplate, null);
9595

96+
/// <summary>
97+
/// Gets or sets the template of the button which moves the user to the numbered page.
98+
/// </summary>
99+
[MarkupOptions(AllowBinding = false, MappingMode = MappingMode.InnerElement)]
100+
[ConstantDataContextChange(typeof(int[]), order: 0)]
101+
[CollectionElementDataContextChange(order: 1)]
102+
public ITemplate? PageNumberTemplate
103+
{
104+
get { return (ITemplate?)GetValue(PageNumberTemplateProperty); }
105+
set { SetValue(PageNumberTemplateProperty, value); }
106+
}
107+
public static readonly DotvvmProperty PageNumberTemplateProperty =
108+
DotvvmProperty.Register<ITemplate?, DataPager>(c => c.PageNumberTemplate, null);
109+
96110
/// <summary>
97111
/// Gets or sets whether a hyperlink should be rendered for the current page number. If set to false, only a plain text is rendered.
98112
/// </summary>
@@ -126,6 +140,27 @@ public bool Enabled
126140
public static readonly DotvvmProperty EnabledProperty =
127141
DotvvmPropertyWithFallback.Register<bool, DataPager>(nameof(Enabled), FormControls.EnabledProperty);
128142

143+
/// <summary>
144+
/// Gets or sets styles for the list item element (&lt;li&gt;) rendered by the component.
145+
/// </summary>
146+
public HtmlCapability ListItemHtmlCapability
147+
{
148+
get => (HtmlCapability)ListItemHtmlCapabilityProperty.GetValue(this);
149+
set => ListItemHtmlCapabilityProperty.SetValue(this, value);
150+
}
151+
public static readonly DotvvmCapabilityProperty ListItemHtmlCapabilityProperty = DotvvmCapabilityProperty.RegisterCapability<HtmlCapability, DataPager>("ListItem");
152+
153+
/// <summary>
154+
/// Gets or sets styles for the link buttons rendered by the component.
155+
/// </summary>
156+
public HtmlCapability LinkHtmlCapability
157+
{
158+
get => (HtmlCapability)LinkHtmlCapabilityProperty.GetValue(this);
159+
set => LinkHtmlCapabilityProperty.SetValue(this, value);
160+
}
161+
public static readonly DotvvmCapabilityProperty LinkHtmlCapabilityProperty = DotvvmCapabilityProperty.RegisterCapability<HtmlCapability, DataPager>("Link");
162+
163+
129164
/// <summary>
130165
/// Gets or sets the (static) command that will be triggered when the DataPager needs to load data (when navigating to different page).
131166
/// 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}" />.
@@ -138,14 +173,36 @@ public ICommandBinding? LoadData
138173
public static readonly DotvvmProperty LoadDataProperty =
139174
DotvvmProperty.Register<ICommandBinding?, DataPager>(nameof(LoadData));
140175

176+
/// <summary>
177+
/// Gets or sets the CSS class to be applied to the currently active page number.
178+
/// </summary>
179+
[MarkupOptions(AllowBinding = false)]
180+
public string ActiveItemCssClass
181+
{
182+
get { return (string)GetValue(ActiveItemCssClassProperty); }
183+
set { SetValue(ActiveItemCssClassProperty, value); }
184+
}
185+
public static readonly DotvvmProperty ActiveItemCssClassProperty
186+
= DotvvmProperty.Register<string, DataPager>(c => c.ActiveItemCssClass, "active");
187+
188+
/// <summary>
189+
/// Gets or sets the CSS class that to be applied to the disabled items.
190+
/// </summary>
191+
[MarkupOptions(AllowBinding = false)]
192+
public string DisabledItemCssClass
193+
{
194+
get { return (string)GetValue(DisabledItemCssClassProperty); }
195+
set { SetValue(DisabledItemCssClassProperty, value); }
196+
}
197+
public static readonly DotvvmProperty DisabledItemCssClassProperty
198+
= DotvvmProperty.Register<string, DataPager>(c => c.DisabledItemCssClass, "disabled");
199+
141200
protected HtmlGenericControl? ContentWrapper { get; set; }
142201
protected HtmlGenericControl? GoToFirstPageButton { get; set; }
143202
protected HtmlGenericControl? GoToPreviousPageButton { get; set; }
144203
protected Repeater? NumberButtonsRepeater { get; set; }
145204
protected HtmlGenericControl? GoToNextPageButton { get; set; }
146205
protected HtmlGenericControl? GoToLastPageButton { get; set; }
147-
protected virtual string ActiveItemCssClass => "active";
148-
protected virtual string DisabledItemCssClass => "disabled";
149206

150207
protected internal override void OnLoad(IDotvvmRequestContext context)
151208
{
@@ -196,7 +253,7 @@ protected virtual void DataBind(Hosting.IDotvvmRequestContext context)
196253
if (pagerBindings.PageNumbers is {})
197254
{
198255
// number fields
199-
var liTemplate = CreatePageNumberButton(globalEnabled, pagerBindings, context);
256+
var liTemplate = CreatePageNumberButton(globalEnabled, PageNumberTemplate, pagerBindings, context);
200257
AddItemCssClass(liTemplate, context);
201258

202259
NumberButtonsRepeater = new Repeater() {
@@ -250,22 +307,23 @@ protected virtual HtmlGenericControl CreateWrapperList()
250307

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

253-
protected virtual HtmlGenericControl CreatePageNumberButton(ValueOrBinding<bool> globalEnabled, DataPagerBindings pagerBindings, IDotvvmRequestContext context)
310+
protected virtual HtmlGenericControl CreatePageNumberButton(ValueOrBinding<bool> globalEnabled, ITemplate? userDefinedContentTemplate, DataPagerBindings pagerBindings, IDotvvmRequestContext context)
254311
{
255-
var liTemplate = new HtmlGenericControl("li");
312+
var liTemplate = new HtmlGenericControl("li", ListItemHtmlCapability);
256313
liTemplate.CssClasses.Add(ActiveItemCssClass, new ValueOrBinding<bool>(pagerBindings.NotNull().IsActivePage.NotNull()));
257-
var link = new LinkButton();
314+
315+
var link = new LinkButton().SetCapability(LinkHtmlCapability);
316+
258317
link.SetBinding(ButtonBase.ClickProperty, pagerBindings.NotNull().GoToPage.NotNull());
259-
SetPageNumberButtonContent(link, pagerBindings, context);
318+
SetPageNumberButtonContent(context, link, pagerBindings, userDefinedContentTemplate);
260319
if (!RenderLinkForCurrentPage) link.SetBinding(IncludeInPageProperty, pagerBindings.IsActivePage.NotNull().Negate());
261320
if (!true.Equals(globalEnabled)) link.SetValue(ButtonBase.EnabledProperty, globalEnabled);
262321
liTemplate.Children.Add(link);
263322

264323
if (!RenderLinkForCurrentPage)
265324
{
266-
var notLink = new Literal();
267-
SetPageNumberSpanContent(notLink, pagerBindings, context);
268-
notLink.RenderSpanElement = true;
325+
var notLink = new HtmlGenericControl("span").SetCapability(LinkHtmlCapability);
326+
SetPageNumberSpanContent(context, notLink, pagerBindings, userDefinedContentTemplate);
269327
notLink.SetBinding(IncludeInPageProperty, pagerBindings.IsActivePage);
270328
liTemplate.Children.Add(notLink);
271329
}
@@ -274,8 +332,10 @@ protected virtual HtmlGenericControl CreatePageNumberButton(ValueOrBinding<bool>
274332

275333
protected virtual HtmlGenericControl CreateNavigationButton(string defaultText, ITemplate? userDefinedContentTemplate, object enabledValue, ICommandBinding clickCommandBindingExpression,IDotvvmRequestContext context)
276334
{
277-
var li = new HtmlGenericControl("li");
278-
var link = new LinkButton();
335+
var li = new HtmlGenericControl("li", ListItemHtmlCapability);
336+
337+
var link = new LinkButton().SetCapability(LinkHtmlCapability);
338+
279339
SetNavigationButtonContent(context, link, defaultText, userDefinedContentTemplate);
280340
link.SetBinding(ButtonBase.ClickProperty, clickCommandBindingExpression);
281341
if (!true.Equals(enabledValue)) link.SetValue(ButtonBase.EnabledProperty, enabledValue);
@@ -295,14 +355,28 @@ protected virtual void SetNavigationButtonContent(IDotvvmRequestContext context,
295355
}
296356
}
297357

298-
protected virtual void SetPageNumberSpanContent(Literal notLink, DataPagerBindings pagerBindings, IDotvvmRequestContext context)
358+
protected virtual void SetPageNumberSpanContent(IDotvvmRequestContext context, HtmlGenericControl span, DataPagerBindings pagerBindings, ITemplate? userDefinedContentTemplate)
299359
{
300-
notLink.SetBinding(Literal.TextProperty, pagerBindings.PageNumberText.NotNull());
360+
if (userDefinedContentTemplate != null)
361+
{
362+
userDefinedContentTemplate.BuildContent(context, span);
363+
}
364+
else
365+
{
366+
span.SetBinding(Literal.TextProperty, pagerBindings.PageNumberText.NotNull());
367+
}
301368
}
302369

303-
protected virtual void SetPageNumberButtonContent(LinkButton link, DataPagerBindings pagerBindings, IDotvvmRequestContext context)
370+
protected virtual void SetPageNumberButtonContent(IDotvvmRequestContext context, LinkButton link, DataPagerBindings pagerBindings, ITemplate? userDefinedContentTemplate)
304371
{
305-
link.SetBinding(ButtonBase.TextProperty, pagerBindings.PageNumberText.NotNull());
372+
if (userDefinedContentTemplate != null)
373+
{
374+
userDefinedContentTemplate.BuildContent(context, link);
375+
}
376+
else
377+
{
378+
link.SetBinding(ButtonBase.TextProperty, pagerBindings.PageNumberText.NotNull());
379+
}
306380
}
307381

308382
protected virtual void AddItemCssClass(HtmlGenericControl item, IDotvvmRequestContext context)
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using DotVVM.Framework.Controls;
2+
using DotVVM.Framework.ViewModel;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
7+
namespace DotVVM.Samples.BasicSamples.ViewModels.ControlSamples.DataPager
8+
{
9+
public class DataPagerTemplatesViewModel : DotvvmViewModelBase
10+
{
11+
public GridViewDataSet<Data> DataSet { get; set; }
12+
13+
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" };
14+
15+
public override Task Init()
16+
{
17+
DataSet = new GridViewDataSet<Data>()
18+
{
19+
PagingOptions = new PagingOptions()
20+
{
21+
PageSize = 3
22+
}
23+
};
24+
return base.Init();
25+
}
26+
27+
public override Task PreRender()
28+
{
29+
if (DataSet.IsRefreshRequired)
30+
{
31+
DataSet.LoadFromQueryable(FakeDB(50));
32+
}
33+
34+
return base.PreRender();
35+
}
36+
37+
private IQueryable<Data> FakeDB(int itemsCreatorCounter)
38+
{
39+
var dbdata = new List<Data>();
40+
for (var i = 0; i < itemsCreatorCounter; i++)
41+
{
42+
dbdata.Add(new Data
43+
{
44+
Text = $"Item {i}"
45+
});
46+
}
47+
return dbdata.AsQueryable();
48+
}
49+
50+
public class Data
51+
{
52+
public string Text { get; set; }
53+
}
54+
}
55+
}

src/Samples/Common/ViewModels/ControlSamples/DataPager/DataPagerViewModel.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ public class DataPagerViewModel : DotvvmViewModelBase
1010
{
1111
public GridViewDataSet<Data> DataSet { get; set; }
1212

13+
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" };
14+
1315
public bool Enabled { get; set; } = true;
1416

1517
public int ItemsInDatabaseCount { get; set; } = 2;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
@viewModel DotVVM.Samples.BasicSamples.ViewModels.ControlSamples.DataPager.DataPagerTemplatesViewModel, DotVVM.Samples.Common
2+
3+
<!DOCTYPE html>
4+
5+
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
6+
<head>
7+
<meta charset="utf-8" />
8+
<title></title>
9+
<style>
10+
.pagination {
11+
list-style-type: none;
12+
display: flex;
13+
align-items: center;
14+
}
15+
.page-item {
16+
margin: 0 1em;
17+
}
18+
.page-link {
19+
text-decoration: none;
20+
}
21+
.disabled {
22+
opacity: 0.3;
23+
}
24+
</style>
25+
</head>
26+
<body>
27+
28+
<h1>Templates in DataPager</h1>
29+
30+
<dot:Repeater DataSource="{value: DataSet}" WrapperTagName="ul">
31+
<ItemTemplate>
32+
<li>{{value: Text}}</li>
33+
</ItemTemplate>
34+
</dot:Repeater>
35+
36+
<dot:DataPager DataSet="{value: DataSet}"
37+
class="pagination"
38+
ListItemclass="page-item"
39+
Linkclass="page-link">
40+
<FirstPageTemplate>◀️◀️</FirstPageTemplate>
41+
<PreviousPageTemplate>◀️</PreviousPageTemplate>
42+
<NextPageTemplate>▶️</NextPageTemplate>
43+
<LastPageTemplate>▶️▶️</LastPageTemplate>
44+
<PageNumberTemplate>
45+
{{value: _root.RomanNumerals[_this]}}
46+
</PageNumberTemplate>
47+
</dot:DataPager>
48+
49+
</body>
50+
</html>
51+
52+

src/Samples/Tests/Abstractions/SamplesRouteUrls.designer.cs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Samples/Tests/Tests/Control/DataPagerTests.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,5 +295,27 @@ IElementWrapper GetPageIndex(int index)
295295
CheckNearPageIndexes(Enumerable.Range(11, 7));
296296
});
297297
}
298+
299+
[Fact]
300+
public void Control_DataPager_DataPagerTemplates()
301+
{
302+
RunInAllBrowsers(browser => {
303+
browser.NavigateToUrl(SamplesRouteUrls.ControlSamples_DataPager_DataPagerTemplates);
304+
305+
var pager = browser.Single(".pagination");
306+
307+
var items = pager.FindElements(".page-item");
308+
items.ThrowIfDifferentCountThan(10);
309+
310+
var content = new[] { "◀️◀️", "◀️", "I", "II", "III", "IV", "V", "VI", "▶️", "▶️▶️" };
311+
for (var i = 0; i < items.Count; i++)
312+
{
313+
var item = items[i];
314+
315+
var link = item.Single(".page-link");
316+
AssertUI.TextEquals(link, content[i]);
317+
}
318+
});
319+
}
298320
}
299321
}

0 commit comments

Comments
 (0)