I've been working on a stackoverflow like pager for my personal use and I've gotten everything working pretty good. Some of my logic is a bit suspect though. Especially the logic in the Pager class itself. I thought I'd try posting this code on here just to see what sort of responses I got. I included my test cases as well. Some of the test names might be weird, but I'll go back and fix that later. Thanks ahead of time!
public class Pager {
public int TotalPages { get; private set; }
public int SelectedItem { get; private set; }
public int PageNumbersToShow { get; set; }
public string CssClass { get; set; }
public Pager(int selectedItem, int totalPages, int pageNumbersToShow = 5) {
this.SelectedItem = selectedItem;
this.TotalPages = totalPages;
this.PageNumbersToShow = pageNumbersToShow;
this.CssClass = "pager fl";
}
public override string ToString() {
var finalString = new StringBuilder();
var pagerDiv = new TagBuilder("div");
pagerDiv.AddCssClass(CssClass);
//prev 1 2 (3)
//prev 1 (2) 3 next
// (1) 2 3 next
if (TotalPages <= PageNumbersToShow) {
for (int i = 1; i <= TotalPages; i++) {
finalString.Append(new PageNumber(i, (SelectedItem == i)).ToString());
}
}
//Greater than pagesize and selected page is less than pagesize
// prev (1) 2 3 4 5 ... 11 next
// prev 1 (2) 3 4 5 ... 11 next
if (SelectedItem < PageNumbersToShow && TotalPages > PageNumbersToShow) {
for (int i = 1; i <= PageNumbersToShow; i++) {
finalString.Append(new PageNumber(i, (SelectedItem == i)).ToString());
}
finalString.Append(new PageNumber().ToString());
finalString.Append(new PageNumber(TotalPages).ToString());
}
//prev 1 ... 7 8 9 10 (11)
//prev 1 ... 7 (8) 9 10 11 next
if (SelectedItem > PageNumbersToShow && TotalPages - (PageNumbersToShow - 1) < SelectedItem) {
finalString.Append(new PageNumber(1).ToString());
finalString.Append(new PageNumber().ToString());
for (int i = (TotalPages - PageNumbersToShow) + 1; i <= TotalPages; i++) {
finalString.Append(new PageNumber(i, (SelectedItem == i)).ToString());
}
}
//prev 1 ... 4 5 (6) 7 8 ... 11 next
if (SelectedItem >= PageNumbersToShow && TotalPages - (PageNumbersToShow - 1) >= SelectedItem) {
finalString.Append(new PageNumber(1).ToString());
finalString.Append(new PageNumber().ToString());
var middle = (PageNumbersToShow / 2);
for (int i = SelectedItem - middle; i <= SelectedItem + middle; i++) {
finalString.Append(new PageNumber(i, (SelectedItem == i)).ToString());
}
finalString.Append(new PageNumber().ToString());
finalString.Append(new PageNumber(TotalPages).ToString());
}
/* Add Previous and Next Link */
if (SelectedItem != 1) {
finalString.Insert(0, new PageNumber(SelectedItem - 1, "prev").ToString());
}
if (SelectedItem != TotalPages) {
finalString.Append(new PageNumber(SelectedItem + 1, "next").ToString());
}
/* Copy final string into div inner HTML */
pagerDiv.InnerHtml = finalString.ToString();
return pagerDiv.ToString();
}
private class PageNumber {
private const string cssClass = "page-numbers";
private const string href = "?page={0}";
private TagBuilder link = new TagBuilder("a");
private TagBuilder span = new TagBuilder("span");
public bool Current { get; private set; }
public int Page { get; private set; }
public PageNumber(int Page, bool Current = false) {
this.Current = Current;
this.Page = Page;
span.AddCssClass(cssClass);
span.SetInnerText(Page.ToString());
}
public PageNumber(int Page, string spanText) {
this.Page = Page;
span.AddCssClass(cssClass + " " + spanText);
span.SetInnerText(spanText + " ");
}
public PageNumber() {
span.AddCssClass(cssClass + " " + "dots");
span.SetInnerText("...");
}
public override string ToString() {
if (Current) {
span.AddCssClass("current");
return span.ToString();
} else {
if (span.ToString().Contains("dots")) {
return span.ToString();
}
link.MergeAttribute("href", string.Format(href, Page));
link.MergeAttribute("title", string.Format("go to page {0}", Page));
link.InnerHtml = span.ToString();
return link.ToString();
}
}
}
}
[TestClass]
public class PagerTests {
// (1)
[TestMethod]
public void Should_Only_Print_Out_One_Span_If_Number_Of_Pages_Is_One() {
//Arrange
var pager = new Pager(1, 1);
//Act
var result = pager.ToString();
//Assert
result.ShouldEqual(@"<div class=""pager fl""><span class=""current page-numbers"">1</span></div>");
}
// (1) 2 3 next
[TestMethod]
public void Should_Not_Print_Out_Previous_If_Selected_Page_Is_First_In_List_Smaller_Than_Five() {
//Arrange
StringBuilder expectedValue = new StringBuilder();
var pager = new Pager(1, 3);
//Act
var result = pager.ToString();
//Assert
expectedValue.Append(@"<div class=""pager fl"">");
expectedValue.Append(@"<span class=""current page-numbers"">1</span>");
expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers"">2</span></a>");
expectedValue.Append(@"<a href=""?page=3"" title=""go to page 3""><span class=""page-numbers"">3</span></a>");
expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers next"">next </span></a>");
expectedValue.Append(@"</div>");
result.ShouldEqual(expectedValue.ToString());
}
// prev 1 2 (3)
[TestMethod]
public void Should_Not_Print_Out_Next_Link_When_Selected_Page_Is_Last_In_List_Smaller_Than_Five() {
//Arrange
StringBuilder expectedValue = new StringBuilder();
var pager = new Pager(3, 3);
//Act
var result = pager.ToString();
//Assert
expectedValue.Append(@"<div class=""pager fl"">");
expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers prev"">prev </span></a>");
expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>");
expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers"">2</span></a>");
expectedValue.Append(@"<span class=""current page-numbers"">3</span>");
expectedValue.Append(@"</div>");
result.ShouldEqual(expectedValue.ToString());
}
// prev 1 (2) 3 next
[TestMethod]
public void Should_Print_Out_Both_Next_And_Previous_When_Selected_Is_Not_First_Or_Last_In_List_Smaller_Than_Five() {
//Arrange
StringBuilder expectedValue = new StringBuilder();
var pager = new Pager(2, 3);
//Act
var result = pager.ToString();
//Assert
expectedValue.Append(@"<div class=""pager fl"">");
expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers prev"">prev </span></a>");
expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>");
expectedValue.Append(@"<span class=""current page-numbers"">2</span>");
expectedValue.Append(@"<a href=""?page=3"" title=""go to page 3""><span class=""page-numbers"">3</span></a>");
expectedValue.Append(@"<a href=""?page=3"" title=""go to page 3""><span class=""page-numbers next"">next </span></a>");
expectedValue.Append(@"</div>");
result.ShouldEqual(expectedValue.ToString());
}
// (1) 2 3 4 5 ... 11 next
[TestMethod]
public void List_Greater_Than_Five_Pages_Generates_Dot_Dot_Dot_Last_Link_With_Page_One_Selcted() {
//Arrange
StringBuilder expectedValue = new StringBuilder();
var pager = new Pager(1, 11);
//Act
var result = pager.ToString();
//Assert
expectedValue.Append(@"<div class=""pager fl"">");
expectedValue.Append(@"<span class=""current page-numbers"">1</span>");
expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers"">2</span></a>");
expectedValue.Append(@"<a href=""?page=3"" title=""go to page 3""><span class=""page-numbers"">3</span></a>");
expectedValue.Append(@"<a href=""?page=4"" title=""go to page 4""><span class=""page-numbers"">4</span></a>");
expectedValue.Append(@"<a href=""?page=5"" title=""go to page 5""><span class=""page-numbers"">5</span></a>");
expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers"">11</span></a>");
expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers next"">next </span></a>");
expectedValue.Append(@"</div>");
result.ShouldEqual(expectedValue.ToString());
}
// prev 1 ... 3 4 (5) 6 7 ... 11 next
[TestMethod]
public void List_Greater_Than_Five_Give_Prev_One_Dot_Dot_Dot_Four_Numbers_Dot_Dot_Dot_Last_Next() {
//Arrange
StringBuilder expectedValue = new StringBuilder();
var pager = new Pager(5, 11);
//Act
var result = pager.ToString();
//Assert
expectedValue.Append(@"<div class=""pager fl"">");
expectedValue.Append(@"<a href=""?page=4"" title=""go to page 4""><span class=""page-numbers prev"">prev </span></a>");
expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>");
expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
expectedValue.Append(@"<a href=""?page=3"" title=""go to page 3""><span class=""page-numbers"">3</span></a>");
expectedValue.Append(@"<a href=""?page=4"" title=""go to page 4""><span class=""page-numbers"">4</span></a>");
expectedValue.Append(@"<span class=""current page-numbers"">5</span>");
expectedValue.Append(@"<a href=""?page=6"" title=""go to page 6""><span class=""page-numbers"">6</span></a>");
expectedValue.Append(@"<a href=""?page=7"" title=""go to page 7""><span class=""page-numbers"">7</span></a>");
expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers"">11</span></a>");
expectedValue.Append(@"<a href=""?page=6"" title=""go to page 6""><span class=""page-numbers next"">next </span></a>");
expectedValue.Append(@"</div>");
result.ShouldEqual(expectedValue.ToString());
}
// prev 1 ... 7 8 9 10 (11)
[TestMethod]
public void When_List_Is_Greater_Than_Five_And_Selected_Is_The_Last_Item() {
//Arrange
StringBuilder expectedValue = new StringBuilder();
var pager = new Pager(11, 11);
//Act
var result = pager.ToString();
//Assert
expectedValue.Append(@"<div class=""pager fl"">");
expectedValue.Append(@"<a href=""?page=10"" title=""go to page 10""><span class=""page-numbers prev"">prev </span></a>");
expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>");
expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
expectedValue.Append(@"<a href=""?page=7"" title=""go to page 7""><span class=""page-numbers"">7</span></a>");
expectedValue.Append(@"<a href=""?page=8"" title=""go to page 8""><span class=""page-numbers"">8</span></a>");
expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers"">9</span></a>");
expectedValue.Append(@"<a href=""?page=10"" title=""go to page 10""><span class=""page-numbers"">10</span></a>");
expectedValue.Append(@"<span class=""current page-numbers"">11</span>");
expectedValue.Append(@"</div>");
result.ShouldEqual(expectedValue.ToString());
}
// prev 1 ... 7 (8) 9 10 11 next
[TestMethod]
public void When_List_Is_Greater_Than_Five_And_Within_PageSize_Of_End_Of_List_And_Last_Item_Is_Not_Selected() {
//Arrange
StringBuilder expectedValue = new StringBuilder();
var pager = new Pager(8, 11);
//Act
var result = pager.ToString();
//Assert
expectedValue.Append(@"<div class=""pager fl"">");
expectedValue.Append(@"<a href=""?page=7"" title=""go to page 7""><span class=""page-numbers prev"">prev </span></a>");
expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>");
expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
expectedValue.Append(@"<a href=""?page=7"" title=""go to page 7""><span class=""page-numbers"">7</span></a>");
expectedValue.Append(@"<span class=""current page-numbers"">8</span>");
expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers"">9</span></a>");
expectedValue.Append(@"<a href=""?page=10"" title=""go to page 10""><span class=""page-numbers"">10</span></a>");
expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers"">11</span></a>");
expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers next"">next </span></a>");
expectedValue.Append(@"</div>");
result.ShouldEqual(expectedValue.ToString());
}
//prev 1 ... 5 6 (7) 8 9 ... 11 next
[TestMethod]
public void When_Selected_Is_One_Less_Than_Page_Size() {
//Arrange
StringBuilder expectedValue = new StringBuilder();
var pager = new Pager(7, 11);
//Act
var result = pager.ToString();
//Assert
expectedValue.Append(@"<div class=""pager fl"">");
expectedValue.Append(@"<a href=""?page=6"" title=""go to page 6""><span class=""page-numbers prev"">prev </span></a>");
expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>");
expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
expectedValue.Append(@"<a href=""?page=5"" title=""go to page 5""><span class=""page-numbers"">5</span></a>");
expectedValue.Append(@"<a href=""?page=6"" title=""go to page 6""><span class=""page-numbers"">6</span></a>");
expectedValue.Append(@"<span class=""current page-numbers"">7</span>");
expectedValue.Append(@"<a href=""?page=8"" title=""go to page 8""><span class=""page-numbers"">8</span></a>");
expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers"">9</span></a>");
expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers"">11</span></a>");
expectedValue.Append(@"<a href=""?page=8"" title=""go to page 8""><span class=""page-numbers next"">next </span></a>");
expectedValue.Append(@"</div>");
result.ShouldEqual(expectedValue.ToString());
}
//prev 1 ... 8 9 (10) 11 12 ... 15 next
[TestMethod]
public void When_Selected_Is_Exactly_Total_Pages_Minus_Page_Size() {
//Arrange
StringBuilder expectedValue = new StringBuilder();
var pager = new Pager(10, 15);
//Act
var result = pager.ToString();
//Assert
expectedValue.Append(@"<div class=""pager fl"">");
expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers prev"">prev </span></a>");
expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>");
expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
expectedValue.Append(@"<a href=""?page=8"" title=""go to page 8""><span class=""page-numbers"">8</span></a>");
expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers"">9</span></a>");
expectedValue.Append(@"<span class=""current page-numbers"">10</span>");
expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers"">11</span></a>");
expectedValue.Append(@"<a href=""?page=12"" title=""go to page 12""><span class=""page-numbers"">12</span></a>");
expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
expectedValue.Append(@"<a href=""?page=15"" title=""go to page 15""><span class=""page-numbers"">15</span></a>");
expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers next"">next </span></a>");
expectedValue.Append(@"</div>");
result.ShouldEqual(expectedValue.ToString());
}
}