From dff585f765e73657824e07a012c0509ac212b467 Mon Sep 17 00:00:00 2001 From: Jonathan Sanford Date: Wed, 29 Oct 2014 10:52:24 -0700 Subject: [PATCH 1/3] Functional Ellipses Option Added PagedListRenderOptions.EnableEllipsisNavigation with the default value of false for backward compatibility. Modified the HtmlHelper.Ellipses method to use the new render option. The pager will use the page before/after the last visible page number as the link target. Added an example to the "Custom Pager Configurations" section of the sample site. --- src/PagedList.Mvc/HtmlHelper.cs | 593 +++++++++--------- src/PagedList.Mvc/PagedListRenderOptions.cs | 6 + src/PagedList.Mvc/Properties/AssemblyInfo.cs | 4 +- .../PagedList.Mvc4.Example.csproj | 2 +- .../Views/TraditionalPaging/Index.cshtml | 3 + 5 files changed, 310 insertions(+), 298 deletions(-) diff --git a/src/PagedList.Mvc/HtmlHelper.cs b/src/PagedList.Mvc/HtmlHelper.cs index cfb6835..2dc9ca0 100644 --- a/src/PagedList.Mvc/HtmlHelper.cs +++ b/src/PagedList.Mvc/HtmlHelper.cs @@ -6,228 +6,231 @@ namespace PagedList.Mvc { - /// - /// Extension methods for generating paging controls that can operate on instances of IPagedList. - /// - public static class HtmlHelper - { - private static TagBuilder WrapInListItem(string text) - { - var li = new TagBuilder("li"); - li.SetInnerText(text); - return li; - } - - private static TagBuilder WrapInListItem(TagBuilder inner, PagedListRenderOptions options, params string[] classes) - { - var li = new TagBuilder("li"); - foreach (var @class in classes) - li.AddCssClass(@class); - if (options.FunctionToTransformEachPageLink != null) - return options.FunctionToTransformEachPageLink(li, inner); - li.InnerHtml = inner.ToString(); - return li; - } - - private static TagBuilder First(IPagedList list, Func generatePageUrl, PagedListRenderOptions options) - { - const int targetPageNumber = 1; - var first = new TagBuilder("a") - { - InnerHtml = string.Format(options.LinkToFirstPageFormat, targetPageNumber) - }; - - if (list.IsFirstPage) - return WrapInListItem(first, options, "PagedList-skipToFirst", "disabled"); - - first.Attributes["href"] = generatePageUrl(targetPageNumber); - return WrapInListItem(first, options, "PagedList-skipToFirst"); - } - - private static TagBuilder Previous(IPagedList list, Func generatePageUrl, PagedListRenderOptions options) - { - var targetPageNumber = list.PageNumber - 1; - var previous = new TagBuilder("a") - { - InnerHtml = string.Format(options.LinkToPreviousPageFormat, targetPageNumber) - }; - previous.Attributes["rel"] = "prev"; - - if (!list.HasPreviousPage) - return WrapInListItem(previous, options, "PagedList-skipToPrevious", "disabled"); - - previous.Attributes["href"] = generatePageUrl(targetPageNumber); - return WrapInListItem(previous, options, "PagedList-skipToPrevious"); - } - - private static TagBuilder Page(int i, IPagedList list, Func generatePageUrl, PagedListRenderOptions options) - { - var format = options.FunctionToDisplayEachPageNumber - ?? (pageNumber => string.Format(options.LinkToIndividualPageFormat, pageNumber)); - var targetPageNumber = i; - var page = new TagBuilder("a"); - page.SetInnerText(format(targetPageNumber)); - - if (i == list.PageNumber) - return WrapInListItem(page, options, "active"); - - page.Attributes["href"] = generatePageUrl(targetPageNumber); - return WrapInListItem(page, options); - } - - private static TagBuilder Next(IPagedList list, Func generatePageUrl, PagedListRenderOptions options) - { - var targetPageNumber = list.PageNumber + 1; - var next = new TagBuilder("a") - { - InnerHtml = string.Format(options.LinkToNextPageFormat, targetPageNumber) - }; - next.Attributes["rel"] = "next"; - - if (!list.HasNextPage) - return WrapInListItem(next, options, "PagedList-skipToNext", "disabled"); - - next.Attributes["href"] = generatePageUrl(targetPageNumber); - return WrapInListItem(next, options, "PagedList-skipToNext"); - } - - private static TagBuilder Last(IPagedList list, Func generatePageUrl, PagedListRenderOptions options) - { - var targetPageNumber = list.PageCount; - var last = new TagBuilder("a") - { - InnerHtml = string.Format(options.LinkToLastPageFormat, targetPageNumber) - }; - - if (list.IsLastPage) - return WrapInListItem(last, options, "PagedList-skipToLast", "disabled"); - - last.Attributes["href"] = generatePageUrl(targetPageNumber); - return WrapInListItem(last, options, "PagedList-skipToLast"); - } - - private static TagBuilder PageCountAndLocationText(IPagedList list, PagedListRenderOptions options) - { - var text = new TagBuilder("a"); - text.SetInnerText(string.Format(options.PageCountAndCurrentLocationFormat, list.PageNumber, list.PageCount)); - - return WrapInListItem(text, options, "PagedList-pageCountAndLocation", "disabled"); - } - - private static TagBuilder ItemSliceAndTotalText(IPagedList list, PagedListRenderOptions options) - { - var text = new TagBuilder("a"); - text.SetInnerText(string.Format(options.ItemSliceAndTotalFormat, list.FirstItemOnPage, list.LastItemOnPage, list.TotalItemCount)); - - return WrapInListItem(text, options, "PagedList-pageCountAndLocation", "disabled"); - } - - private static TagBuilder Ellipses(PagedListRenderOptions options) - { - var a = new TagBuilder("a") - { - InnerHtml = options.EllipsesFormat - }; - - return WrapInListItem(a, options, "PagedList-ellipses", "disabled"); - } - - /// - /// Displays a configurable paging control for instances of PagedList. - /// - ///This method is meant to hook off HtmlHelper as an extension method. - ///The PagedList to use as the data source. - ///A function that takes the page number of the desired page and returns a URL-string that will load that page. - ///Outputs the paging control HTML. - public static MvcHtmlString PagedListPager(this System.Web.Mvc.HtmlHelper html, - IPagedList list, - Func generatePageUrl) - { - return PagedListPager(html, list, generatePageUrl, new PagedListRenderOptions()); - } - - /// - /// Displays a configurable paging control for instances of PagedList. - /// - ///This method is meant to hook off HtmlHelper as an extension method. - ///The PagedList to use as the data source. - ///A function that takes the page number of the desired page and returns a URL-string that will load that page. - ///Formatting options. - ///Outputs the paging control HTML. - public static MvcHtmlString PagedListPager(this System.Web.Mvc.HtmlHelper html, - IPagedList list, - Func generatePageUrl, - PagedListRenderOptions options) - { + /// + /// Extension methods for generating paging controls that can operate on instances of IPagedList. + /// + public static class HtmlHelper + { + private static TagBuilder WrapInListItem(string text) + { + var li = new TagBuilder("li"); + li.SetInnerText(text); + return li; + } + + private static TagBuilder WrapInListItem(TagBuilder inner, PagedListRenderOptions options, params string[] classes) + { + var li = new TagBuilder("li"); + foreach (var @class in classes) + li.AddCssClass(@class); + if (options.FunctionToTransformEachPageLink != null) + return options.FunctionToTransformEachPageLink(li, inner); + li.InnerHtml = inner.ToString(); + return li; + } + + private static TagBuilder First(IPagedList list, Func generatePageUrl, PagedListRenderOptions options) + { + const int targetPageNumber = 1; + var first = new TagBuilder("a") + { + InnerHtml = string.Format(options.LinkToFirstPageFormat, targetPageNumber) + }; + + if (list.IsFirstPage) + return WrapInListItem(first, options, "PagedList-skipToFirst", "disabled"); + + first.Attributes["href"] = generatePageUrl(targetPageNumber); + return WrapInListItem(first, options, "PagedList-skipToFirst"); + } + + private static TagBuilder Previous(IPagedList list, Func generatePageUrl, PagedListRenderOptions options) + { + var targetPageNumber = list.PageNumber - 1; + var previous = new TagBuilder("a") + { + InnerHtml = string.Format(options.LinkToPreviousPageFormat, targetPageNumber) + }; + previous.Attributes["rel"] = "prev"; + + if (!list.HasPreviousPage) + return WrapInListItem(previous, options, "PagedList-skipToPrevious", "disabled"); + + previous.Attributes["href"] = generatePageUrl(targetPageNumber); + return WrapInListItem(previous, options, "PagedList-skipToPrevious"); + } + + private static TagBuilder Page(int i, IPagedList list, Func generatePageUrl, PagedListRenderOptions options) + { + var format = options.FunctionToDisplayEachPageNumber + ?? (pageNumber => string.Format(options.LinkToIndividualPageFormat, pageNumber)); + var targetPageNumber = i; + var page = new TagBuilder("a"); + page.SetInnerText(format(targetPageNumber)); + + if (i == list.PageNumber) + return WrapInListItem(page, options, "active"); + + page.Attributes["href"] = generatePageUrl(targetPageNumber); + return WrapInListItem(page, options); + } + + private static TagBuilder Next(IPagedList list, Func generatePageUrl, PagedListRenderOptions options) + { + var targetPageNumber = list.PageNumber + 1; + var next = new TagBuilder("a") + { + InnerHtml = string.Format(options.LinkToNextPageFormat, targetPageNumber) + }; + next.Attributes["rel"] = "next"; + + if (!list.HasNextPage) + return WrapInListItem(next, options, "PagedList-skipToNext", "disabled"); + + next.Attributes["href"] = generatePageUrl(targetPageNumber); + return WrapInListItem(next, options, "PagedList-skipToNext"); + } + + private static TagBuilder Last(IPagedList list, Func generatePageUrl, PagedListRenderOptions options) + { + var targetPageNumber = list.PageCount; + var last = new TagBuilder("a") + { + InnerHtml = string.Format(options.LinkToLastPageFormat, targetPageNumber) + }; + + if (list.IsLastPage) + return WrapInListItem(last, options, "PagedList-skipToLast", "disabled"); + + last.Attributes["href"] = generatePageUrl(targetPageNumber); + return WrapInListItem(last, options, "PagedList-skipToLast"); + } + + private static TagBuilder PageCountAndLocationText(IPagedList list, PagedListRenderOptions options) + { + var text = new TagBuilder("a"); + text.SetInnerText(string.Format(options.PageCountAndCurrentLocationFormat, list.PageNumber, list.PageCount)); + + return WrapInListItem(text, options, "PagedList-pageCountAndLocation", "disabled"); + } + + private static TagBuilder ItemSliceAndTotalText(IPagedList list, PagedListRenderOptions options) + { + var text = new TagBuilder("a"); + text.SetInnerText(string.Format(options.ItemSliceAndTotalFormat, list.FirstItemOnPage, list.LastItemOnPage, list.TotalItemCount)); + + return WrapInListItem(text, options, "PagedList-pageCountAndLocation", "disabled"); + } + + private static TagBuilder Ellipses(PagedListRenderOptions options, Func generatePageUrl, int targetPageNumber) + { + var a = new TagBuilder("a") + { + InnerHtml = options.EllipsesFormat + }; + + if (options.EnableEllipsesNavigation) + a.Attributes["href"] = generatePageUrl(targetPageNumber); + + return WrapInListItem(a, options, "PagedList-ellipses", options.EnableEllipsesNavigation ? null : "disabled"); + } + + /// + /// Displays a configurable paging control for instances of PagedList. + /// + ///This method is meant to hook off HtmlHelper as an extension method. + ///The PagedList to use as the data source. + ///A function that takes the page number of the desired page and returns a URL-string that will load that page. + ///Outputs the paging control HTML. + public static MvcHtmlString PagedListPager(this System.Web.Mvc.HtmlHelper html, + IPagedList list, + Func generatePageUrl) + { + return PagedListPager(html, list, generatePageUrl, new PagedListRenderOptions()); + } + + /// + /// Displays a configurable paging control for instances of PagedList. + /// + ///This method is meant to hook off HtmlHelper as an extension method. + ///The PagedList to use as the data source. + ///A function that takes the page number of the desired page and returns a URL-string that will load that page. + ///Formatting options. + ///Outputs the paging control HTML. + public static MvcHtmlString PagedListPager(this System.Web.Mvc.HtmlHelper html, + IPagedList list, + Func generatePageUrl, + PagedListRenderOptions options) + { if (options.Display == PagedListDisplayMode.Never || (options.Display == PagedListDisplayMode.IfNeeded && list.PageCount <= 1)) return null; - var listItemLinks = new List(); + var listItemLinks = new List(); //calculate start and end of range of page numbers var firstPageToDisplay = 1; - var lastPageToDisplay = list.PageCount; - var pageNumbersToDisplay = lastPageToDisplay; + var lastPageToDisplay = list.PageCount; + var pageNumbersToDisplay = lastPageToDisplay; if (options.MaximumPageNumbersToDisplay.HasValue && list.PageCount > options.MaximumPageNumbersToDisplay) { - // cannot fit all pages into pager + // cannot fit all pages into pager var maxPageNumbersToDisplay = options.MaximumPageNumbersToDisplay.Value; firstPageToDisplay = list.PageNumber - maxPageNumbersToDisplay / 2; if (firstPageToDisplay < 1) firstPageToDisplay = 1; pageNumbersToDisplay = maxPageNumbersToDisplay; - lastPageToDisplay = firstPageToDisplay + pageNumbersToDisplay - 1; + lastPageToDisplay = firstPageToDisplay + pageNumbersToDisplay - 1; if (lastPageToDisplay > list.PageCount) firstPageToDisplay = list.PageCount - maxPageNumbersToDisplay + 1; } - //first - if (options.DisplayLinkToFirstPage == PagedListDisplayMode.Always || (options.DisplayLinkToFirstPage == PagedListDisplayMode.IfNeeded && firstPageToDisplay > 1)) - listItemLinks.Add(First(list, generatePageUrl, options)); - - //previous - if (options.DisplayLinkToPreviousPage == PagedListDisplayMode.Always || (options.DisplayLinkToPreviousPage == PagedListDisplayMode.IfNeeded && !list.IsFirstPage)) - listItemLinks.Add(Previous(list, generatePageUrl, options)); - - //text - if (options.DisplayPageCountAndCurrentLocation) - listItemLinks.Add(PageCountAndLocationText(list, options)); - - //text - if (options.DisplayItemSliceAndTotal) - listItemLinks.Add(ItemSliceAndTotalText(list, options)); - - //page - if (options.DisplayLinkToIndividualPages) - { - //if there are previous page numbers not displayed, show an ellipsis - if (options.DisplayEllipsesWhenNotShowingAllPageNumbers && firstPageToDisplay > 1) - listItemLinks.Add(Ellipses(options)); - - foreach (var i in Enumerable.Range(firstPageToDisplay, pageNumbersToDisplay)) - { - //show delimiter between page numbers - if (i > firstPageToDisplay && !string.IsNullOrWhiteSpace(options.DelimiterBetweenPageNumbers)) - listItemLinks.Add(WrapInListItem(options.DelimiterBetweenPageNumbers)); - - //show page number link - listItemLinks.Add(Page(i, list, generatePageUrl, options)); - } - - //if there are subsequent page numbers not displayed, show an ellipsis - if (options.DisplayEllipsesWhenNotShowingAllPageNumbers && (firstPageToDisplay + pageNumbersToDisplay - 1) < list.PageCount) - listItemLinks.Add(Ellipses(options)); - } - - //next - if (options.DisplayLinkToNextPage == PagedListDisplayMode.Always || (options.DisplayLinkToNextPage == PagedListDisplayMode.IfNeeded && !list.IsLastPage)) - listItemLinks.Add(Next(list, generatePageUrl, options)); - - //last + //first + if (options.DisplayLinkToFirstPage == PagedListDisplayMode.Always || (options.DisplayLinkToFirstPage == PagedListDisplayMode.IfNeeded && firstPageToDisplay > 1)) + listItemLinks.Add(First(list, generatePageUrl, options)); + + //previous + if (options.DisplayLinkToPreviousPage == PagedListDisplayMode.Always || (options.DisplayLinkToPreviousPage == PagedListDisplayMode.IfNeeded && !list.IsFirstPage)) + listItemLinks.Add(Previous(list, generatePageUrl, options)); + + //text + if (options.DisplayPageCountAndCurrentLocation) + listItemLinks.Add(PageCountAndLocationText(list, options)); + + //text + if (options.DisplayItemSliceAndTotal) + listItemLinks.Add(ItemSliceAndTotalText(list, options)); + + //page + if (options.DisplayLinkToIndividualPages) + { + //if there are previous page numbers not displayed, show an ellipsis + if (options.DisplayEllipsesWhenNotShowingAllPageNumbers && firstPageToDisplay > 1) + listItemLinks.Add(Ellipses(options, generatePageUrl, firstPageToDisplay - 1)); + + foreach (var i in Enumerable.Range(firstPageToDisplay, pageNumbersToDisplay)) + { + //show delimiter between page numbers + if (i > firstPageToDisplay && !string.IsNullOrWhiteSpace(options.DelimiterBetweenPageNumbers)) + listItemLinks.Add(WrapInListItem(options.DelimiterBetweenPageNumbers)); + + //show page number link + listItemLinks.Add(Page(i, list, generatePageUrl, options)); + } + + //if there are subsequent page numbers not displayed, show an ellipsis + if (options.DisplayEllipsesWhenNotShowingAllPageNumbers && (firstPageToDisplay + pageNumbersToDisplay - 1) < list.PageCount) + listItemLinks.Add(Ellipses(options, generatePageUrl, (firstPageToDisplay + pageNumbersToDisplay))); + } + + //next + if (options.DisplayLinkToNextPage == PagedListDisplayMode.Always || (options.DisplayLinkToNextPage == PagedListDisplayMode.IfNeeded && !list.IsLastPage)) + listItemLinks.Add(Next(list, generatePageUrl, options)); + + //last if (options.DisplayLinkToLastPage == PagedListDisplayMode.Always || (options.DisplayLinkToLastPage == PagedListDisplayMode.IfNeeded && lastPageToDisplay < list.PageCount)) - listItemLinks.Add(Last(list, generatePageUrl, options)); + listItemLinks.Add(Last(list, generatePageUrl, options)); - if(listItemLinks.Any()) + if (listItemLinks.Any()) { //append class to first item in list? if (!string.IsNullOrWhiteSpace(options.ClassToApplyToFirstListItemInPager)) @@ -243,96 +246,96 @@ public static MvcHtmlString PagedListPager(this System.Web.Mvc.HtmlHelper html, li.AddCssClass(c); } - //collapse all of the list items into one big string - var listItemLinksString = listItemLinks.Aggregate( - new StringBuilder(), - (sb, listItem) => sb.Append(listItem.ToString()), - sb=> sb.ToString() - ); - - var ul = new TagBuilder("ul") - { - InnerHtml = listItemLinksString - }; - foreach (var c in options.UlElementClasses ?? Enumerable.Empty()) - ul.AddCssClass(c); - - var outerDiv = new TagBuilder("div"); - foreach(var c in options.ContainerDivClasses ?? Enumerable.Empty()) - outerDiv.AddCssClass(c); - outerDiv.InnerHtml = ul.ToString(); - - return new MvcHtmlString(outerDiv.ToString()); - } - - /// - /// Displays a configurable "Go To Page:" form for instances of PagedList. - /// - ///This method is meant to hook off HtmlHelper as an extension method. - ///The PagedList to use as the data source. - ///The URL this form should submit the GET request to. - ///Outputs the "Go To Page:" form HTML. - public static MvcHtmlString PagedListGoToPageForm(this System.Web.Mvc.HtmlHelper html, - IPagedList list, - string formAction) - { - return PagedListGoToPageForm(html, list, formAction, "page"); - } - - /// - /// Displays a configurable "Go To Page:" form for instances of PagedList. - /// - ///This method is meant to hook off HtmlHelper as an extension method. - ///The PagedList to use as the data source. - ///The URL this form should submit the GET request to. - ///The querystring key this form should submit the new page number as. - ///Outputs the "Go To Page:" form HTML. - public static MvcHtmlString PagedListGoToPageForm(this System.Web.Mvc.HtmlHelper html, - IPagedList list, - string formAction, - string inputFieldName) - { - return PagedListGoToPageForm(html, list, formAction, new GoToFormRenderOptions(inputFieldName)); - } - - /// - /// Displays a configurable "Go To Page:" form for instances of PagedList. - /// - ///This method is meant to hook off HtmlHelper as an extension method. - ///The PagedList to use as the data source. - ///The URL this form should submit the GET request to. - ///Formatting options. - ///Outputs the "Go To Page:" form HTML. - public static MvcHtmlString PagedListGoToPageForm(this System.Web.Mvc.HtmlHelper html, - IPagedList list, - string formAction, - GoToFormRenderOptions options) - { - var form = new TagBuilder("form"); - form.AddCssClass("PagedList-goToPage"); - form.Attributes.Add("action", formAction); - form.Attributes.Add("method", "get"); - - var fieldset = new TagBuilder("fieldset"); - - var label = new TagBuilder("label"); - label.Attributes.Add("for", options.InputFieldName); - label.SetInnerText(options.LabelFormat); - - var input = new TagBuilder("input"); - input.Attributes.Add("type", options.InputFieldType); - input.Attributes.Add("name", options.InputFieldName); - input.Attributes.Add("value", list.PageNumber.ToString()); - - var submit = new TagBuilder("input"); - submit.Attributes.Add("type", "submit"); - submit.Attributes.Add("value", options.SubmitButtonFormat); - - fieldset.InnerHtml = label.ToString(); - fieldset.InnerHtml += input.ToString(TagRenderMode.SelfClosing); - fieldset.InnerHtml += submit.ToString(TagRenderMode.SelfClosing); - form.InnerHtml = fieldset.ToString(); - return new MvcHtmlString(form.ToString()); - } - } + //collapse all of the list items into one big string + var listItemLinksString = listItemLinks.Aggregate( + new StringBuilder(), + (sb, listItem) => sb.Append(listItem.ToString()), + sb => sb.ToString() + ); + + var ul = new TagBuilder("ul") + { + InnerHtml = listItemLinksString + }; + foreach (var c in options.UlElementClasses ?? Enumerable.Empty()) + ul.AddCssClass(c); + + var outerDiv = new TagBuilder("div"); + foreach (var c in options.ContainerDivClasses ?? Enumerable.Empty()) + outerDiv.AddCssClass(c); + outerDiv.InnerHtml = ul.ToString(); + + return new MvcHtmlString(outerDiv.ToString()); + } + + /// + /// Displays a configurable "Go To Page:" form for instances of PagedList. + /// + ///This method is meant to hook off HtmlHelper as an extension method. + ///The PagedList to use as the data source. + ///The URL this form should submit the GET request to. + ///Outputs the "Go To Page:" form HTML. + public static MvcHtmlString PagedListGoToPageForm(this System.Web.Mvc.HtmlHelper html, + IPagedList list, + string formAction) + { + return PagedListGoToPageForm(html, list, formAction, "page"); + } + + /// + /// Displays a configurable "Go To Page:" form for instances of PagedList. + /// + ///This method is meant to hook off HtmlHelper as an extension method. + ///The PagedList to use as the data source. + ///The URL this form should submit the GET request to. + ///The querystring key this form should submit the new page number as. + ///Outputs the "Go To Page:" form HTML. + public static MvcHtmlString PagedListGoToPageForm(this System.Web.Mvc.HtmlHelper html, + IPagedList list, + string formAction, + string inputFieldName) + { + return PagedListGoToPageForm(html, list, formAction, new GoToFormRenderOptions(inputFieldName)); + } + + /// + /// Displays a configurable "Go To Page:" form for instances of PagedList. + /// + ///This method is meant to hook off HtmlHelper as an extension method. + ///The PagedList to use as the data source. + ///The URL this form should submit the GET request to. + ///Formatting options. + ///Outputs the "Go To Page:" form HTML. + public static MvcHtmlString PagedListGoToPageForm(this System.Web.Mvc.HtmlHelper html, + IPagedList list, + string formAction, + GoToFormRenderOptions options) + { + var form = new TagBuilder("form"); + form.AddCssClass("PagedList-goToPage"); + form.Attributes.Add("action", formAction); + form.Attributes.Add("method", "get"); + + var fieldset = new TagBuilder("fieldset"); + + var label = new TagBuilder("label"); + label.Attributes.Add("for", options.InputFieldName); + label.SetInnerText(options.LabelFormat); + + var input = new TagBuilder("input"); + input.Attributes.Add("type", options.InputFieldType); + input.Attributes.Add("name", options.InputFieldName); + input.Attributes.Add("value", list.PageNumber.ToString()); + + var submit = new TagBuilder("input"); + submit.Attributes.Add("type", "submit"); + submit.Attributes.Add("value", options.SubmitButtonFormat); + + fieldset.InnerHtml = label.ToString(); + fieldset.InnerHtml += input.ToString(TagRenderMode.SelfClosing); + fieldset.InnerHtml += submit.ToString(TagRenderMode.SelfClosing); + form.InnerHtml = fieldset.ToString(); + return new MvcHtmlString(form.ToString()); + } + } } \ No newline at end of file diff --git a/src/PagedList.Mvc/PagedListRenderOptions.cs b/src/PagedList.Mvc/PagedListRenderOptions.cs index 985c53b..d0314e5 100644 --- a/src/PagedList.Mvc/PagedListRenderOptions.cs +++ b/src/PagedList.Mvc/PagedListRenderOptions.cs @@ -38,6 +38,7 @@ public PagedListRenderOptions() ContainerDivClasses = new [] { "pagination-container" }; UlElementClasses = new[] { "pagination" }; LiElementClasses = Enumerable.Empty(); + EnableEllipsesNavigation = false; } /// @@ -205,6 +206,11 @@ public PagedListRenderOptions() /// public Func FunctionToTransformEachPageLink { get; set; } + /// + /// Enables or disables the navigation functionality of the ellipses + /// + public bool EnableEllipsesNavigation { get; set; } + /// /// Enables ASP.NET MVC's unobtrusive AJAX feature. An XHR request will retrieve HTML from the clicked page and replace the innerHtml of the provided element ID. /// diff --git a/src/PagedList.Mvc/Properties/AssemblyInfo.cs b/src/PagedList.Mvc/Properties/AssemblyInfo.cs index 63525c2..4f90892 100644 --- a/src/PagedList.Mvc/Properties/AssemblyInfo.cs +++ b/src/PagedList.Mvc/Properties/AssemblyInfo.cs @@ -7,13 +7,13 @@ [assembly: AssemblyCompany("Troy Goode")] [assembly: AssemblyProduct("PagedList.Mvc")] [assembly: AssemblyCopyright("MIT License")] -[assembly: AssemblyVersion("4.5")] +[assembly: AssemblyVersion("4.5.0.1")] [assembly: CLSCompliant(true)] [assembly: ComVisible(false)] [assembly: Guid("eb684fee-2094-4833-ae61-f9bfcab34abd")] [assembly: AllowPartiallyTrustedCallers()] -[assembly: AssemblyFileVersion("4.5")] +[assembly: AssemblyFileVersion("4.5.0.1")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/src/PagedList.Mvc4.Example/PagedList.Mvc4.Example.csproj b/src/PagedList.Mvc4.Example/PagedList.Mvc4.Example.csproj index 4c22e87..5143904 100644 --- a/src/PagedList.Mvc4.Example/PagedList.Mvc4.Example.csproj +++ b/src/PagedList.Mvc4.Example/PagedList.Mvc4.Example.csproj @@ -331,7 +331,7 @@ True True - 0 + 59919 / http://localhost:2232/ False diff --git a/src/PagedList.Mvc4.Example/Views/TraditionalPaging/Index.cshtml b/src/PagedList.Mvc4.Example/Views/TraditionalPaging/Index.cshtml index ebe448e..5da2ef0 100644 --- a/src/PagedList.Mvc4.Example/Views/TraditionalPaging/Index.cshtml +++ b/src/PagedList.Mvc4.Example/Views/TraditionalPaging/Index.cshtml @@ -47,6 +47,9 @@

Custom Pager Configurations

+

Functional Ellipses

+@Html.PagedListPager((IPagedList)ViewBag.Names, page => Url.Action("Index", new { page }), new PagedListRenderOptions() { EnableEllipsesNavigation = true }) +

Custom Wording (Spanish Translation Example)

@Html.PagedListPager((IPagedList)ViewBag.Names, page => Url.Action("Index", new { page }), new PagedListRenderOptions { LinkToFirstPageFormat = "<< Primera", LinkToPreviousPageFormat = "< Anterior", LinkToNextPageFormat = "Siguiente >", LinkToLastPageFormat = "Última >>" }) From e24cf97456ad1287645f7755211a95ae67aeabde Mon Sep 17 00:00:00 2001 From: Jonathan Sanford Date: Wed, 29 Oct 2014 11:48:46 -0700 Subject: [PATCH 2/3] Revert "Functional Ellipses Option" This reverts commit dff585f765e73657824e07a012c0509ac212b467. --- src/PagedList.Mvc/HtmlHelper.cs | 593 +++++++++--------- src/PagedList.Mvc/PagedListRenderOptions.cs | 6 - src/PagedList.Mvc/Properties/AssemblyInfo.cs | 4 +- .../PagedList.Mvc4.Example.csproj | 2 +- .../Views/TraditionalPaging/Index.cshtml | 3 - 5 files changed, 298 insertions(+), 310 deletions(-) diff --git a/src/PagedList.Mvc/HtmlHelper.cs b/src/PagedList.Mvc/HtmlHelper.cs index 2dc9ca0..cfb6835 100644 --- a/src/PagedList.Mvc/HtmlHelper.cs +++ b/src/PagedList.Mvc/HtmlHelper.cs @@ -6,231 +6,228 @@ namespace PagedList.Mvc { - /// - /// Extension methods for generating paging controls that can operate on instances of IPagedList. - /// - public static class HtmlHelper - { - private static TagBuilder WrapInListItem(string text) - { - var li = new TagBuilder("li"); - li.SetInnerText(text); - return li; - } - - private static TagBuilder WrapInListItem(TagBuilder inner, PagedListRenderOptions options, params string[] classes) - { - var li = new TagBuilder("li"); - foreach (var @class in classes) - li.AddCssClass(@class); - if (options.FunctionToTransformEachPageLink != null) - return options.FunctionToTransformEachPageLink(li, inner); - li.InnerHtml = inner.ToString(); - return li; - } - - private static TagBuilder First(IPagedList list, Func generatePageUrl, PagedListRenderOptions options) - { - const int targetPageNumber = 1; - var first = new TagBuilder("a") - { - InnerHtml = string.Format(options.LinkToFirstPageFormat, targetPageNumber) - }; - - if (list.IsFirstPage) - return WrapInListItem(first, options, "PagedList-skipToFirst", "disabled"); - - first.Attributes["href"] = generatePageUrl(targetPageNumber); - return WrapInListItem(first, options, "PagedList-skipToFirst"); - } - - private static TagBuilder Previous(IPagedList list, Func generatePageUrl, PagedListRenderOptions options) - { - var targetPageNumber = list.PageNumber - 1; - var previous = new TagBuilder("a") - { - InnerHtml = string.Format(options.LinkToPreviousPageFormat, targetPageNumber) - }; - previous.Attributes["rel"] = "prev"; - - if (!list.HasPreviousPage) - return WrapInListItem(previous, options, "PagedList-skipToPrevious", "disabled"); - - previous.Attributes["href"] = generatePageUrl(targetPageNumber); - return WrapInListItem(previous, options, "PagedList-skipToPrevious"); - } - - private static TagBuilder Page(int i, IPagedList list, Func generatePageUrl, PagedListRenderOptions options) - { - var format = options.FunctionToDisplayEachPageNumber - ?? (pageNumber => string.Format(options.LinkToIndividualPageFormat, pageNumber)); - var targetPageNumber = i; - var page = new TagBuilder("a"); - page.SetInnerText(format(targetPageNumber)); - - if (i == list.PageNumber) - return WrapInListItem(page, options, "active"); - - page.Attributes["href"] = generatePageUrl(targetPageNumber); - return WrapInListItem(page, options); - } - - private static TagBuilder Next(IPagedList list, Func generatePageUrl, PagedListRenderOptions options) - { - var targetPageNumber = list.PageNumber + 1; - var next = new TagBuilder("a") - { - InnerHtml = string.Format(options.LinkToNextPageFormat, targetPageNumber) - }; - next.Attributes["rel"] = "next"; - - if (!list.HasNextPage) - return WrapInListItem(next, options, "PagedList-skipToNext", "disabled"); - - next.Attributes["href"] = generatePageUrl(targetPageNumber); - return WrapInListItem(next, options, "PagedList-skipToNext"); - } - - private static TagBuilder Last(IPagedList list, Func generatePageUrl, PagedListRenderOptions options) - { - var targetPageNumber = list.PageCount; - var last = new TagBuilder("a") - { - InnerHtml = string.Format(options.LinkToLastPageFormat, targetPageNumber) - }; - - if (list.IsLastPage) - return WrapInListItem(last, options, "PagedList-skipToLast", "disabled"); - - last.Attributes["href"] = generatePageUrl(targetPageNumber); - return WrapInListItem(last, options, "PagedList-skipToLast"); - } - - private static TagBuilder PageCountAndLocationText(IPagedList list, PagedListRenderOptions options) - { - var text = new TagBuilder("a"); - text.SetInnerText(string.Format(options.PageCountAndCurrentLocationFormat, list.PageNumber, list.PageCount)); - - return WrapInListItem(text, options, "PagedList-pageCountAndLocation", "disabled"); - } - - private static TagBuilder ItemSliceAndTotalText(IPagedList list, PagedListRenderOptions options) - { - var text = new TagBuilder("a"); - text.SetInnerText(string.Format(options.ItemSliceAndTotalFormat, list.FirstItemOnPage, list.LastItemOnPage, list.TotalItemCount)); - - return WrapInListItem(text, options, "PagedList-pageCountAndLocation", "disabled"); - } - - private static TagBuilder Ellipses(PagedListRenderOptions options, Func generatePageUrl, int targetPageNumber) - { - var a = new TagBuilder("a") - { - InnerHtml = options.EllipsesFormat - }; - - if (options.EnableEllipsesNavigation) - a.Attributes["href"] = generatePageUrl(targetPageNumber); - - return WrapInListItem(a, options, "PagedList-ellipses", options.EnableEllipsesNavigation ? null : "disabled"); - } - - /// - /// Displays a configurable paging control for instances of PagedList. - /// - ///This method is meant to hook off HtmlHelper as an extension method. - ///The PagedList to use as the data source. - ///A function that takes the page number of the desired page and returns a URL-string that will load that page. - ///Outputs the paging control HTML. - public static MvcHtmlString PagedListPager(this System.Web.Mvc.HtmlHelper html, - IPagedList list, - Func generatePageUrl) - { - return PagedListPager(html, list, generatePageUrl, new PagedListRenderOptions()); - } - - /// - /// Displays a configurable paging control for instances of PagedList. - /// - ///This method is meant to hook off HtmlHelper as an extension method. - ///The PagedList to use as the data source. - ///A function that takes the page number of the desired page and returns a URL-string that will load that page. - ///Formatting options. - ///Outputs the paging control HTML. - public static MvcHtmlString PagedListPager(this System.Web.Mvc.HtmlHelper html, - IPagedList list, - Func generatePageUrl, - PagedListRenderOptions options) - { + /// + /// Extension methods for generating paging controls that can operate on instances of IPagedList. + /// + public static class HtmlHelper + { + private static TagBuilder WrapInListItem(string text) + { + var li = new TagBuilder("li"); + li.SetInnerText(text); + return li; + } + + private static TagBuilder WrapInListItem(TagBuilder inner, PagedListRenderOptions options, params string[] classes) + { + var li = new TagBuilder("li"); + foreach (var @class in classes) + li.AddCssClass(@class); + if (options.FunctionToTransformEachPageLink != null) + return options.FunctionToTransformEachPageLink(li, inner); + li.InnerHtml = inner.ToString(); + return li; + } + + private static TagBuilder First(IPagedList list, Func generatePageUrl, PagedListRenderOptions options) + { + const int targetPageNumber = 1; + var first = new TagBuilder("a") + { + InnerHtml = string.Format(options.LinkToFirstPageFormat, targetPageNumber) + }; + + if (list.IsFirstPage) + return WrapInListItem(first, options, "PagedList-skipToFirst", "disabled"); + + first.Attributes["href"] = generatePageUrl(targetPageNumber); + return WrapInListItem(first, options, "PagedList-skipToFirst"); + } + + private static TagBuilder Previous(IPagedList list, Func generatePageUrl, PagedListRenderOptions options) + { + var targetPageNumber = list.PageNumber - 1; + var previous = new TagBuilder("a") + { + InnerHtml = string.Format(options.LinkToPreviousPageFormat, targetPageNumber) + }; + previous.Attributes["rel"] = "prev"; + + if (!list.HasPreviousPage) + return WrapInListItem(previous, options, "PagedList-skipToPrevious", "disabled"); + + previous.Attributes["href"] = generatePageUrl(targetPageNumber); + return WrapInListItem(previous, options, "PagedList-skipToPrevious"); + } + + private static TagBuilder Page(int i, IPagedList list, Func generatePageUrl, PagedListRenderOptions options) + { + var format = options.FunctionToDisplayEachPageNumber + ?? (pageNumber => string.Format(options.LinkToIndividualPageFormat, pageNumber)); + var targetPageNumber = i; + var page = new TagBuilder("a"); + page.SetInnerText(format(targetPageNumber)); + + if (i == list.PageNumber) + return WrapInListItem(page, options, "active"); + + page.Attributes["href"] = generatePageUrl(targetPageNumber); + return WrapInListItem(page, options); + } + + private static TagBuilder Next(IPagedList list, Func generatePageUrl, PagedListRenderOptions options) + { + var targetPageNumber = list.PageNumber + 1; + var next = new TagBuilder("a") + { + InnerHtml = string.Format(options.LinkToNextPageFormat, targetPageNumber) + }; + next.Attributes["rel"] = "next"; + + if (!list.HasNextPage) + return WrapInListItem(next, options, "PagedList-skipToNext", "disabled"); + + next.Attributes["href"] = generatePageUrl(targetPageNumber); + return WrapInListItem(next, options, "PagedList-skipToNext"); + } + + private static TagBuilder Last(IPagedList list, Func generatePageUrl, PagedListRenderOptions options) + { + var targetPageNumber = list.PageCount; + var last = new TagBuilder("a") + { + InnerHtml = string.Format(options.LinkToLastPageFormat, targetPageNumber) + }; + + if (list.IsLastPage) + return WrapInListItem(last, options, "PagedList-skipToLast", "disabled"); + + last.Attributes["href"] = generatePageUrl(targetPageNumber); + return WrapInListItem(last, options, "PagedList-skipToLast"); + } + + private static TagBuilder PageCountAndLocationText(IPagedList list, PagedListRenderOptions options) + { + var text = new TagBuilder("a"); + text.SetInnerText(string.Format(options.PageCountAndCurrentLocationFormat, list.PageNumber, list.PageCount)); + + return WrapInListItem(text, options, "PagedList-pageCountAndLocation", "disabled"); + } + + private static TagBuilder ItemSliceAndTotalText(IPagedList list, PagedListRenderOptions options) + { + var text = new TagBuilder("a"); + text.SetInnerText(string.Format(options.ItemSliceAndTotalFormat, list.FirstItemOnPage, list.LastItemOnPage, list.TotalItemCount)); + + return WrapInListItem(text, options, "PagedList-pageCountAndLocation", "disabled"); + } + + private static TagBuilder Ellipses(PagedListRenderOptions options) + { + var a = new TagBuilder("a") + { + InnerHtml = options.EllipsesFormat + }; + + return WrapInListItem(a, options, "PagedList-ellipses", "disabled"); + } + + /// + /// Displays a configurable paging control for instances of PagedList. + /// + ///This method is meant to hook off HtmlHelper as an extension method. + ///The PagedList to use as the data source. + ///A function that takes the page number of the desired page and returns a URL-string that will load that page. + ///Outputs the paging control HTML. + public static MvcHtmlString PagedListPager(this System.Web.Mvc.HtmlHelper html, + IPagedList list, + Func generatePageUrl) + { + return PagedListPager(html, list, generatePageUrl, new PagedListRenderOptions()); + } + + /// + /// Displays a configurable paging control for instances of PagedList. + /// + ///This method is meant to hook off HtmlHelper as an extension method. + ///The PagedList to use as the data source. + ///A function that takes the page number of the desired page and returns a URL-string that will load that page. + ///Formatting options. + ///Outputs the paging control HTML. + public static MvcHtmlString PagedListPager(this System.Web.Mvc.HtmlHelper html, + IPagedList list, + Func generatePageUrl, + PagedListRenderOptions options) + { if (options.Display == PagedListDisplayMode.Never || (options.Display == PagedListDisplayMode.IfNeeded && list.PageCount <= 1)) return null; - var listItemLinks = new List(); + var listItemLinks = new List(); //calculate start and end of range of page numbers var firstPageToDisplay = 1; - var lastPageToDisplay = list.PageCount; - var pageNumbersToDisplay = lastPageToDisplay; + var lastPageToDisplay = list.PageCount; + var pageNumbersToDisplay = lastPageToDisplay; if (options.MaximumPageNumbersToDisplay.HasValue && list.PageCount > options.MaximumPageNumbersToDisplay) { - // cannot fit all pages into pager + // cannot fit all pages into pager var maxPageNumbersToDisplay = options.MaximumPageNumbersToDisplay.Value; firstPageToDisplay = list.PageNumber - maxPageNumbersToDisplay / 2; if (firstPageToDisplay < 1) firstPageToDisplay = 1; pageNumbersToDisplay = maxPageNumbersToDisplay; - lastPageToDisplay = firstPageToDisplay + pageNumbersToDisplay - 1; + lastPageToDisplay = firstPageToDisplay + pageNumbersToDisplay - 1; if (lastPageToDisplay > list.PageCount) firstPageToDisplay = list.PageCount - maxPageNumbersToDisplay + 1; } - //first - if (options.DisplayLinkToFirstPage == PagedListDisplayMode.Always || (options.DisplayLinkToFirstPage == PagedListDisplayMode.IfNeeded && firstPageToDisplay > 1)) - listItemLinks.Add(First(list, generatePageUrl, options)); - - //previous - if (options.DisplayLinkToPreviousPage == PagedListDisplayMode.Always || (options.DisplayLinkToPreviousPage == PagedListDisplayMode.IfNeeded && !list.IsFirstPage)) - listItemLinks.Add(Previous(list, generatePageUrl, options)); - - //text - if (options.DisplayPageCountAndCurrentLocation) - listItemLinks.Add(PageCountAndLocationText(list, options)); - - //text - if (options.DisplayItemSliceAndTotal) - listItemLinks.Add(ItemSliceAndTotalText(list, options)); - - //page - if (options.DisplayLinkToIndividualPages) - { - //if there are previous page numbers not displayed, show an ellipsis - if (options.DisplayEllipsesWhenNotShowingAllPageNumbers && firstPageToDisplay > 1) - listItemLinks.Add(Ellipses(options, generatePageUrl, firstPageToDisplay - 1)); - - foreach (var i in Enumerable.Range(firstPageToDisplay, pageNumbersToDisplay)) - { - //show delimiter between page numbers - if (i > firstPageToDisplay && !string.IsNullOrWhiteSpace(options.DelimiterBetweenPageNumbers)) - listItemLinks.Add(WrapInListItem(options.DelimiterBetweenPageNumbers)); - - //show page number link - listItemLinks.Add(Page(i, list, generatePageUrl, options)); - } - - //if there are subsequent page numbers not displayed, show an ellipsis - if (options.DisplayEllipsesWhenNotShowingAllPageNumbers && (firstPageToDisplay + pageNumbersToDisplay - 1) < list.PageCount) - listItemLinks.Add(Ellipses(options, generatePageUrl, (firstPageToDisplay + pageNumbersToDisplay))); - } - - //next - if (options.DisplayLinkToNextPage == PagedListDisplayMode.Always || (options.DisplayLinkToNextPage == PagedListDisplayMode.IfNeeded && !list.IsLastPage)) - listItemLinks.Add(Next(list, generatePageUrl, options)); - - //last + //first + if (options.DisplayLinkToFirstPage == PagedListDisplayMode.Always || (options.DisplayLinkToFirstPage == PagedListDisplayMode.IfNeeded && firstPageToDisplay > 1)) + listItemLinks.Add(First(list, generatePageUrl, options)); + + //previous + if (options.DisplayLinkToPreviousPage == PagedListDisplayMode.Always || (options.DisplayLinkToPreviousPage == PagedListDisplayMode.IfNeeded && !list.IsFirstPage)) + listItemLinks.Add(Previous(list, generatePageUrl, options)); + + //text + if (options.DisplayPageCountAndCurrentLocation) + listItemLinks.Add(PageCountAndLocationText(list, options)); + + //text + if (options.DisplayItemSliceAndTotal) + listItemLinks.Add(ItemSliceAndTotalText(list, options)); + + //page + if (options.DisplayLinkToIndividualPages) + { + //if there are previous page numbers not displayed, show an ellipsis + if (options.DisplayEllipsesWhenNotShowingAllPageNumbers && firstPageToDisplay > 1) + listItemLinks.Add(Ellipses(options)); + + foreach (var i in Enumerable.Range(firstPageToDisplay, pageNumbersToDisplay)) + { + //show delimiter between page numbers + if (i > firstPageToDisplay && !string.IsNullOrWhiteSpace(options.DelimiterBetweenPageNumbers)) + listItemLinks.Add(WrapInListItem(options.DelimiterBetweenPageNumbers)); + + //show page number link + listItemLinks.Add(Page(i, list, generatePageUrl, options)); + } + + //if there are subsequent page numbers not displayed, show an ellipsis + if (options.DisplayEllipsesWhenNotShowingAllPageNumbers && (firstPageToDisplay + pageNumbersToDisplay - 1) < list.PageCount) + listItemLinks.Add(Ellipses(options)); + } + + //next + if (options.DisplayLinkToNextPage == PagedListDisplayMode.Always || (options.DisplayLinkToNextPage == PagedListDisplayMode.IfNeeded && !list.IsLastPage)) + listItemLinks.Add(Next(list, generatePageUrl, options)); + + //last if (options.DisplayLinkToLastPage == PagedListDisplayMode.Always || (options.DisplayLinkToLastPage == PagedListDisplayMode.IfNeeded && lastPageToDisplay < list.PageCount)) - listItemLinks.Add(Last(list, generatePageUrl, options)); + listItemLinks.Add(Last(list, generatePageUrl, options)); - if (listItemLinks.Any()) + if(listItemLinks.Any()) { //append class to first item in list? if (!string.IsNullOrWhiteSpace(options.ClassToApplyToFirstListItemInPager)) @@ -246,96 +243,96 @@ public static MvcHtmlString PagedListPager(this System.Web.Mvc.HtmlHelper html, li.AddCssClass(c); } - //collapse all of the list items into one big string - var listItemLinksString = listItemLinks.Aggregate( - new StringBuilder(), - (sb, listItem) => sb.Append(listItem.ToString()), - sb => sb.ToString() - ); - - var ul = new TagBuilder("ul") - { - InnerHtml = listItemLinksString - }; - foreach (var c in options.UlElementClasses ?? Enumerable.Empty()) - ul.AddCssClass(c); - - var outerDiv = new TagBuilder("div"); - foreach (var c in options.ContainerDivClasses ?? Enumerable.Empty()) - outerDiv.AddCssClass(c); - outerDiv.InnerHtml = ul.ToString(); - - return new MvcHtmlString(outerDiv.ToString()); - } - - /// - /// Displays a configurable "Go To Page:" form for instances of PagedList. - /// - ///This method is meant to hook off HtmlHelper as an extension method. - ///The PagedList to use as the data source. - ///The URL this form should submit the GET request to. - ///Outputs the "Go To Page:" form HTML. - public static MvcHtmlString PagedListGoToPageForm(this System.Web.Mvc.HtmlHelper html, - IPagedList list, - string formAction) - { - return PagedListGoToPageForm(html, list, formAction, "page"); - } - - /// - /// Displays a configurable "Go To Page:" form for instances of PagedList. - /// - ///This method is meant to hook off HtmlHelper as an extension method. - ///The PagedList to use as the data source. - ///The URL this form should submit the GET request to. - ///The querystring key this form should submit the new page number as. - ///Outputs the "Go To Page:" form HTML. - public static MvcHtmlString PagedListGoToPageForm(this System.Web.Mvc.HtmlHelper html, - IPagedList list, - string formAction, - string inputFieldName) - { - return PagedListGoToPageForm(html, list, formAction, new GoToFormRenderOptions(inputFieldName)); - } - - /// - /// Displays a configurable "Go To Page:" form for instances of PagedList. - /// - ///This method is meant to hook off HtmlHelper as an extension method. - ///The PagedList to use as the data source. - ///The URL this form should submit the GET request to. - ///Formatting options. - ///Outputs the "Go To Page:" form HTML. - public static MvcHtmlString PagedListGoToPageForm(this System.Web.Mvc.HtmlHelper html, - IPagedList list, - string formAction, - GoToFormRenderOptions options) - { - var form = new TagBuilder("form"); - form.AddCssClass("PagedList-goToPage"); - form.Attributes.Add("action", formAction); - form.Attributes.Add("method", "get"); - - var fieldset = new TagBuilder("fieldset"); - - var label = new TagBuilder("label"); - label.Attributes.Add("for", options.InputFieldName); - label.SetInnerText(options.LabelFormat); - - var input = new TagBuilder("input"); - input.Attributes.Add("type", options.InputFieldType); - input.Attributes.Add("name", options.InputFieldName); - input.Attributes.Add("value", list.PageNumber.ToString()); - - var submit = new TagBuilder("input"); - submit.Attributes.Add("type", "submit"); - submit.Attributes.Add("value", options.SubmitButtonFormat); - - fieldset.InnerHtml = label.ToString(); - fieldset.InnerHtml += input.ToString(TagRenderMode.SelfClosing); - fieldset.InnerHtml += submit.ToString(TagRenderMode.SelfClosing); - form.InnerHtml = fieldset.ToString(); - return new MvcHtmlString(form.ToString()); - } - } + //collapse all of the list items into one big string + var listItemLinksString = listItemLinks.Aggregate( + new StringBuilder(), + (sb, listItem) => sb.Append(listItem.ToString()), + sb=> sb.ToString() + ); + + var ul = new TagBuilder("ul") + { + InnerHtml = listItemLinksString + }; + foreach (var c in options.UlElementClasses ?? Enumerable.Empty()) + ul.AddCssClass(c); + + var outerDiv = new TagBuilder("div"); + foreach(var c in options.ContainerDivClasses ?? Enumerable.Empty()) + outerDiv.AddCssClass(c); + outerDiv.InnerHtml = ul.ToString(); + + return new MvcHtmlString(outerDiv.ToString()); + } + + /// + /// Displays a configurable "Go To Page:" form for instances of PagedList. + /// + ///This method is meant to hook off HtmlHelper as an extension method. + ///The PagedList to use as the data source. + ///The URL this form should submit the GET request to. + ///Outputs the "Go To Page:" form HTML. + public static MvcHtmlString PagedListGoToPageForm(this System.Web.Mvc.HtmlHelper html, + IPagedList list, + string formAction) + { + return PagedListGoToPageForm(html, list, formAction, "page"); + } + + /// + /// Displays a configurable "Go To Page:" form for instances of PagedList. + /// + ///This method is meant to hook off HtmlHelper as an extension method. + ///The PagedList to use as the data source. + ///The URL this form should submit the GET request to. + ///The querystring key this form should submit the new page number as. + ///Outputs the "Go To Page:" form HTML. + public static MvcHtmlString PagedListGoToPageForm(this System.Web.Mvc.HtmlHelper html, + IPagedList list, + string formAction, + string inputFieldName) + { + return PagedListGoToPageForm(html, list, formAction, new GoToFormRenderOptions(inputFieldName)); + } + + /// + /// Displays a configurable "Go To Page:" form for instances of PagedList. + /// + ///This method is meant to hook off HtmlHelper as an extension method. + ///The PagedList to use as the data source. + ///The URL this form should submit the GET request to. + ///Formatting options. + ///Outputs the "Go To Page:" form HTML. + public static MvcHtmlString PagedListGoToPageForm(this System.Web.Mvc.HtmlHelper html, + IPagedList list, + string formAction, + GoToFormRenderOptions options) + { + var form = new TagBuilder("form"); + form.AddCssClass("PagedList-goToPage"); + form.Attributes.Add("action", formAction); + form.Attributes.Add("method", "get"); + + var fieldset = new TagBuilder("fieldset"); + + var label = new TagBuilder("label"); + label.Attributes.Add("for", options.InputFieldName); + label.SetInnerText(options.LabelFormat); + + var input = new TagBuilder("input"); + input.Attributes.Add("type", options.InputFieldType); + input.Attributes.Add("name", options.InputFieldName); + input.Attributes.Add("value", list.PageNumber.ToString()); + + var submit = new TagBuilder("input"); + submit.Attributes.Add("type", "submit"); + submit.Attributes.Add("value", options.SubmitButtonFormat); + + fieldset.InnerHtml = label.ToString(); + fieldset.InnerHtml += input.ToString(TagRenderMode.SelfClosing); + fieldset.InnerHtml += submit.ToString(TagRenderMode.SelfClosing); + form.InnerHtml = fieldset.ToString(); + return new MvcHtmlString(form.ToString()); + } + } } \ No newline at end of file diff --git a/src/PagedList.Mvc/PagedListRenderOptions.cs b/src/PagedList.Mvc/PagedListRenderOptions.cs index d0314e5..985c53b 100644 --- a/src/PagedList.Mvc/PagedListRenderOptions.cs +++ b/src/PagedList.Mvc/PagedListRenderOptions.cs @@ -38,7 +38,6 @@ public PagedListRenderOptions() ContainerDivClasses = new [] { "pagination-container" }; UlElementClasses = new[] { "pagination" }; LiElementClasses = Enumerable.Empty(); - EnableEllipsesNavigation = false; } /// @@ -206,11 +205,6 @@ public PagedListRenderOptions() /// public Func FunctionToTransformEachPageLink { get; set; } - /// - /// Enables or disables the navigation functionality of the ellipses - /// - public bool EnableEllipsesNavigation { get; set; } - /// /// Enables ASP.NET MVC's unobtrusive AJAX feature. An XHR request will retrieve HTML from the clicked page and replace the innerHtml of the provided element ID. /// diff --git a/src/PagedList.Mvc/Properties/AssemblyInfo.cs b/src/PagedList.Mvc/Properties/AssemblyInfo.cs index 4f90892..63525c2 100644 --- a/src/PagedList.Mvc/Properties/AssemblyInfo.cs +++ b/src/PagedList.Mvc/Properties/AssemblyInfo.cs @@ -7,13 +7,13 @@ [assembly: AssemblyCompany("Troy Goode")] [assembly: AssemblyProduct("PagedList.Mvc")] [assembly: AssemblyCopyright("MIT License")] -[assembly: AssemblyVersion("4.5.0.1")] +[assembly: AssemblyVersion("4.5")] [assembly: CLSCompliant(true)] [assembly: ComVisible(false)] [assembly: Guid("eb684fee-2094-4833-ae61-f9bfcab34abd")] [assembly: AllowPartiallyTrustedCallers()] -[assembly: AssemblyFileVersion("4.5.0.1")] +[assembly: AssemblyFileVersion("4.5")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/src/PagedList.Mvc4.Example/PagedList.Mvc4.Example.csproj b/src/PagedList.Mvc4.Example/PagedList.Mvc4.Example.csproj index 5143904..4c22e87 100644 --- a/src/PagedList.Mvc4.Example/PagedList.Mvc4.Example.csproj +++ b/src/PagedList.Mvc4.Example/PagedList.Mvc4.Example.csproj @@ -331,7 +331,7 @@ True True - 59919 + 0 / http://localhost:2232/ False diff --git a/src/PagedList.Mvc4.Example/Views/TraditionalPaging/Index.cshtml b/src/PagedList.Mvc4.Example/Views/TraditionalPaging/Index.cshtml index 5da2ef0..ebe448e 100644 --- a/src/PagedList.Mvc4.Example/Views/TraditionalPaging/Index.cshtml +++ b/src/PagedList.Mvc4.Example/Views/TraditionalPaging/Index.cshtml @@ -47,9 +47,6 @@

Custom Pager Configurations

-

Functional Ellipses

-@Html.PagedListPager((IPagedList)ViewBag.Names, page => Url.Action("Index", new { page }), new PagedListRenderOptions() { EnableEllipsesNavigation = true }) -

Custom Wording (Spanish Translation Example)

@Html.PagedListPager((IPagedList)ViewBag.Names, page => Url.Action("Index", new { page }), new PagedListRenderOptions { LinkToFirstPageFormat = "<< Primera", LinkToPreviousPageFormat = "< Anterior", LinkToNextPageFormat = "Siguiente >", LinkToLastPageFormat = "Última >>" }) From 674abed0d250280d0bc5494ee6b656ad25acbacb Mon Sep 17 00:00:00 2001 From: Jonathan Sanford Date: Wed, 29 Oct 2014 11:55:04 -0700 Subject: [PATCH 3/3] Functional Ellipses Option Added PagedListRenderOptions.EnableEllipsisNavigation with the default value of false for backward compatibility. Modified the HtmlHelper.Ellipses method to use the new render option. The pager will use the page before/after the last visible page number as the link target. Added an example to the "Custom Pager Configurations" section of the sample site. --- src/PagedList.Mvc/HtmlHelper.cs | 23 +++++++++++-------- src/PagedList.Mvc/PagedListRenderOptions.cs | 6 +++++ .../Views/TraditionalPaging/Index.cshtml | 3 +++ 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/PagedList.Mvc/HtmlHelper.cs b/src/PagedList.Mvc/HtmlHelper.cs index cfb6835..60db6e3 100644 --- a/src/PagedList.Mvc/HtmlHelper.cs +++ b/src/PagedList.Mvc/HtmlHelper.cs @@ -122,15 +122,18 @@ private static TagBuilder ItemSliceAndTotalText(IPagedList list, PagedListRender return WrapInListItem(text, options, "PagedList-pageCountAndLocation", "disabled"); } - private static TagBuilder Ellipses(PagedListRenderOptions options) - { - var a = new TagBuilder("a") - { - InnerHtml = options.EllipsesFormat - }; + private static TagBuilder Ellipses(PagedListRenderOptions options, Func generatePageUrl, int targetPageNumber) + { + var a = new TagBuilder("a") + { + InnerHtml = options.EllipsesFormat + }; - return WrapInListItem(a, options, "PagedList-ellipses", "disabled"); - } + if (options.EnableEllipsesNavigation) + a.Attributes["href"] = generatePageUrl(targetPageNumber); + + return WrapInListItem(a, options, "PagedList-ellipses", options.EnableEllipsesNavigation ? null : "disabled"); + } /// /// Displays a configurable paging control for instances of PagedList. @@ -202,7 +205,7 @@ public static MvcHtmlString PagedListPager(this System.Web.Mvc.HtmlHelper html, { //if there are previous page numbers not displayed, show an ellipsis if (options.DisplayEllipsesWhenNotShowingAllPageNumbers && firstPageToDisplay > 1) - listItemLinks.Add(Ellipses(options)); + listItemLinks.Add(Ellipses(options, generatePageUrl, firstPageToDisplay - 1)); foreach (var i in Enumerable.Range(firstPageToDisplay, pageNumbersToDisplay)) { @@ -216,7 +219,7 @@ public static MvcHtmlString PagedListPager(this System.Web.Mvc.HtmlHelper html, //if there are subsequent page numbers not displayed, show an ellipsis if (options.DisplayEllipsesWhenNotShowingAllPageNumbers && (firstPageToDisplay + pageNumbersToDisplay - 1) < list.PageCount) - listItemLinks.Add(Ellipses(options)); + listItemLinks.Add(Ellipses(options, generatePageUrl, (firstPageToDisplay + pageNumbersToDisplay))); } //next diff --git a/src/PagedList.Mvc/PagedListRenderOptions.cs b/src/PagedList.Mvc/PagedListRenderOptions.cs index 985c53b..30e183a 100644 --- a/src/PagedList.Mvc/PagedListRenderOptions.cs +++ b/src/PagedList.Mvc/PagedListRenderOptions.cs @@ -38,6 +38,7 @@ public PagedListRenderOptions() ContainerDivClasses = new [] { "pagination-container" }; UlElementClasses = new[] { "pagination" }; LiElementClasses = Enumerable.Empty(); + EnableEllipsesNavigation = false; } /// @@ -204,6 +205,11 @@ public PagedListRenderOptions() /// An extension point which allows you to fully customize the anchor tags used for clickable pages, as well as navigation features such as Next, Last, etc. /// public Func FunctionToTransformEachPageLink { get; set; } + + /// + /// Enables or disables the navigation functionality of the ellipses + /// + public bool EnableEllipsesNavigation { get; set; } /// /// Enables ASP.NET MVC's unobtrusive AJAX feature. An XHR request will retrieve HTML from the clicked page and replace the innerHtml of the provided element ID. diff --git a/src/PagedList.Mvc4.Example/Views/TraditionalPaging/Index.cshtml b/src/PagedList.Mvc4.Example/Views/TraditionalPaging/Index.cshtml index ebe448e..5da2ef0 100644 --- a/src/PagedList.Mvc4.Example/Views/TraditionalPaging/Index.cshtml +++ b/src/PagedList.Mvc4.Example/Views/TraditionalPaging/Index.cshtml @@ -47,6 +47,9 @@

Custom Pager Configurations

+

Functional Ellipses

+@Html.PagedListPager((IPagedList)ViewBag.Names, page => Url.Action("Index", new { page }), new PagedListRenderOptions() { EnableEllipsesNavigation = true }) +

Custom Wording (Spanish Translation Example)

@Html.PagedListPager((IPagedList)ViewBag.Names, page => Url.Action("Index", new { page }), new PagedListRenderOptions { LinkToFirstPageFormat = "<< Primera", LinkToPreviousPageFormat = "< Anterior", LinkToNextPageFormat = "Siguiente >", LinkToLastPageFormat = "Última >>" })