Fixing and improving Pager and List theming

--HG--
branch : 1.x
This commit is contained in:
Sebastien Ros
2013-02-08 12:36:58 -08:00
parent 006bef1de8
commit d50b0f8eee
2 changed files with 115 additions and 44 deletions

View File

@@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Web; using System.Web;
@@ -28,20 +27,24 @@ namespace Orchard.Core.Shapes {
private readonly Work<WorkContext> _workContext; private readonly Work<WorkContext> _workContext;
private readonly Work<IResourceManager> _resourceManager; private readonly Work<IResourceManager> _resourceManager;
private readonly Work<IHttpContextAccessor> _httpContextAccessor; private readonly Work<IHttpContextAccessor> _httpContextAccessor;
private readonly Work<IShapeFactory> _shapeFactory;
public CoreShapes( public CoreShapes(
Work<WorkContext> workContext, Work<WorkContext> workContext,
Work<IResourceManager> resourceManager, Work<IResourceManager> resourceManager,
Work<IHttpContextAccessor> httpContextAccessor Work<IHttpContextAccessor> httpContextAccessor,
Work<IShapeFactory> shapeFactory
) { ) {
_workContext = workContext; _workContext = workContext;
_resourceManager = resourceManager; _resourceManager = resourceManager;
_httpContextAccessor = httpContextAccessor; _httpContextAccessor = httpContextAccessor;
_shapeFactory = shapeFactory;
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
} }
public Localizer T { get; set; } public Localizer T { get; set; }
public dynamic New { get { return _shapeFactory.Value; } }
public void Discover(ShapeTableBuilder builder) { public void Discover(ShapeTableBuilder builder) {
// the root page shape named 'Layout' is wrapped with 'Document' // the root page shape named 'Layout' is wrapped with 'Document'
@@ -490,49 +493,49 @@ namespace Orchard.Core.Shapes {
routeData.Remove(pageKey); // to keep from having "page=1" in the query string routeData.Remove(pageKey); // to keep from having "page=1" in the query string
} }
// first // first
Shape.Add(Display.Pager_First(Value: firstText, RouteValues: routeData, Pager: Shape)); Shape.Add(New.Pager_First(Value: firstText, RouteValues: new RouteValueDictionary(routeData), Pager: Shape));
// previous // previous
if (currentPage > 2) { // also to keep from having "page=1" in the query string if (currentPage > 2) { // also to keep from having "page=1" in the query string
routeData[pageKey] = currentPage - 1; routeData[pageKey] = currentPage - 1;
} }
Shape.Add(Display.Pager_Previous(Value: previousText, RouteValues: routeData, Pager: Shape)); Shape.Add(New.Pager_Previous(Value: previousText, RouteValues: new RouteValueDictionary(routeData), Pager: Shape));
} }
// gap at the beginning of the pager // gap at the beginning of the pager
if (firstPage > 1 && numberOfPagesToShow > 0) { if (firstPage > 1 && numberOfPagesToShow > 0) {
Shape.Add(Display.Pager_Gap(Value: gapText, Pager: Shape)); Shape.Add(New.Pager_Gap(Value: gapText, Pager: Shape));
} }
// page numbers // page numbers
if (numberOfPagesToShow > 0 && firstPage != lastPage) { if (numberOfPagesToShow > 0) {
for (var p = firstPage; p <= lastPage; p++) { for (var p = firstPage; p <= lastPage; p++) {
if (p == currentPage) { if (p == currentPage) {
Shape.Add(Display.Pager_CurrentPage(Value: p, RouteValues: routeData, Pager: Shape)); Shape.Add(New.Pager_CurrentPage(Value: p, RouteValues: new RouteValueDictionary(routeData), Pager: Shape));
} }
else { else {
if (p == 1) if (p == 1)
routeData.Remove(pageKey); routeData.Remove(pageKey);
else else
routeData[pageKey] = p; routeData[pageKey] = p;
Shape.Add(Display.Pager_Link(Value: p, RouteValues: routeData, Pager: Shape)); Shape.Add(New.Pager_Link(Value: p, RouteValues: new RouteValueDictionary(routeData), Pager: Shape));
} }
} }
} }
// gap at the end of the pager // gap at the end of the pager
if (lastPage < totalPageCount && numberOfPagesToShow > 0) { if (lastPage < totalPageCount && numberOfPagesToShow > 0) {
Shape.Add(Display.Pager_Gap(Value: gapText, Pager: Shape)); Shape.Add(New.Pager_Gap(Value: gapText, Pager: Shape));
} }
// next and last pages // next and last pages
if (Page < totalPageCount) { if (Page < totalPageCount) {
// next // next
routeData[pageKey] = Page + 1; routeData[pageKey] = Page + 1;
Shape.Add(Display.Pager_Next(Value: nextText, RouteValues: routeData, Pager: Shape)); Shape.Add(New.Pager_Next(Value: nextText, RouteValues: new RouteValueDictionary(routeData), Pager: Shape));
// last // last
routeData[pageKey] = totalPageCount; routeData[pageKey] = totalPageCount;
Shape.Add(Display.Pager_Last(Value: lastText, RouteValues: routeData, Pager: Shape)); Shape.Add(New.Pager_Last(Value: lastText, RouteValues: new RouteValueDictionary(routeData), Pager: Shape));
} }
return Display(Shape); return Display(Shape);
@@ -562,7 +565,7 @@ namespace Orchard.Core.Shapes {
[Shape] [Shape]
public IHtmlString Pager_CurrentPage(HtmlHelper Html, dynamic Display, object Value) { public IHtmlString Pager_CurrentPage(HtmlHelper Html, dynamic Display, object Value) {
var tagBuilder = new TagBuilder("span"); var tagBuilder = new TagBuilder("span");
tagBuilder.InnerHtml = Html.Encode(Value is string ? (string)Value : Display(Value)); tagBuilder.InnerHtml = EncodeOrDisplay(Value, Display, Html).ToString();
return MvcHtmlString.Create(tagBuilder.ToString()); return MvcHtmlString.Create(tagBuilder.ToString());
} }
@@ -583,21 +586,13 @@ namespace Orchard.Core.Shapes {
[Shape] [Shape]
public IHtmlString Pager_Link(HtmlHelper Html, dynamic Shape, dynamic Display, object Value) { public IHtmlString Pager_Link(HtmlHelper Html, dynamic Shape, dynamic Display, object Value) {
var RouteValues = (object)Shape.RouteValues; Shape.Metadata.Alternates.Clear();
RouteValueDictionary rvd; Shape.Metadata.Type = "ActionLink";
if (RouteValues == null) { return Display(Shape);
rvd = new RouteValueDictionary();
}
else {
rvd = RouteValues is RouteValueDictionary ? (RouteValueDictionary)RouteValues : new RouteValueDictionary(RouteValues);
}
string value = Html.Encode(Value is string ? (string)Value : Display(Value));
return @Html.ActionLink(value, (string)rvd["action"], (string)rvd["controller"], rvd, null);
} }
[Shape] [Shape]
public IHtmlString ActionLink(HtmlHelper Html, dynamic Shape, dynamic Display, object Value) { public IHtmlString ActionLink(HtmlHelper Html, UrlHelper Url, dynamic Shape, dynamic Display, object Value) {
var RouteValues = (object)Shape.RouteValues; var RouteValues = (object)Shape.RouteValues;
RouteValueDictionary rvd; RouteValueDictionary rvd;
if (RouteValues == null) { if (RouteValues == null) {
@@ -607,14 +602,22 @@ namespace Orchard.Core.Shapes {
rvd = RouteValues is RouteValueDictionary ? (RouteValueDictionary)RouteValues : new RouteValueDictionary(RouteValues); rvd = RouteValues is RouteValueDictionary ? (RouteValueDictionary)RouteValues : new RouteValueDictionary(RouteValues);
} }
string value = Html.Encode(Value is string ? (string)Value : Display(Value)); var action = Url.Action((string)rvd["action"], (string)rvd["controller"], rvd);
return @Html.ActionLink(value, (string)rvd["action"], (string)rvd["controller"], rvd, null);
IEnumerable<string> classes = Shape.Classes;
IDictionary<string, string> attributes = Shape.Attributes;
attributes.Add("href", action);
string id = Shape.Id;
var tag = GetTagBuilder("a", id, classes, attributes);
tag.InnerHtml = EncodeOrDisplay(Value, Display, Html).ToString();
return Html.Raw(tag.ToString());
} }
[Shape] [Shape]
public IHtmlString Pager_Gap(HtmlHelper Html, dynamic Display, object Value) { public IHtmlString Pager_Gap(HtmlHelper Html, dynamic Display, object Value) {
var tagBuilder = new TagBuilder("span"); var tagBuilder = new TagBuilder("span");
tagBuilder.InnerHtml = Html.Encode(Value is string ? (string)Value : Display(Value)); tagBuilder.InnerHtml = EncodeOrDisplay(Value, Display, Html).ToString();
return MvcHtmlString.Create(tagBuilder.ToString()); return MvcHtmlString.Create(tagBuilder.ToString());
} }
@@ -628,37 +631,88 @@ namespace Orchard.Core.Shapes {
string Id, string Id,
IEnumerable<string> Classes, IEnumerable<string> Classes,
IDictionary<string, string> Attributes, IDictionary<string, string> Attributes,
string ItemTag,
IEnumerable<string> ItemClasses, IEnumerable<string> ItemClasses,
IDictionary<string, string> ItemAttributes) { IDictionary<string, string> ItemAttributes) {
if (Items == null) if (Items == null)
return; return;
var itemDisplayOutputs = Items.Select(item => Display(item)).Where(output => !string.IsNullOrWhiteSpace(output.ToHtmlString())).ToList(); // prevent multiple enumerations
var count = itemDisplayOutputs.Count(); var items = Items.ToList();
// var itemDisplayOutputs = Items.Select(item => Display(item)).Where(output => !string.IsNullOrWhiteSpace(output.ToHtmlString())).ToList();
var count = items.Count();
if (count < 1) if (count < 1)
return; return;
var listTagName = string.IsNullOrEmpty(Tag) ? "ul" : Tag; string listTagName = null;
const string itemTagName = "li";
var listTag = GetTagBuilder(listTagName, Id, Classes, Attributes); if (Tag != "-") {
Output.Write(listTag.ToString(TagRenderMode.StartTag)); listTagName = string.IsNullOrEmpty(Tag) ? "ul" : Tag;
}
var listTag = String.IsNullOrEmpty(listTagName) ? null : GetTagBuilder(listTagName, Id, Classes, Attributes);
string itemTagName = null;
if (ItemTag != "-") {
itemTagName = string.IsNullOrEmpty(ItemTag) ? "li" : ItemTag;
}
if (listTag != null) {
Output.Write(listTag.ToString(TagRenderMode.StartTag));
}
var itemTags = new List<TagBuilder>();
var itemOutputs = new List<string>();
// give the item shape the possibility to alter its container tag
var index = 0; var index = 0;
foreach (var itemDisplayOutput in itemDisplayOutputs) { foreach (var item in items) {
var itemTag = GetTagBuilder(itemTagName, null, ItemClasses, ItemAttributes);
if (index == 0) var itemTag = String.IsNullOrEmpty(itemTagName) ? null : GetTagBuilder(itemTagName, null, ItemClasses, ItemAttributes);
itemTag.AddCssClass("first");
if (index == count - 1) if (item is IShape) {
itemTag.AddCssClass("last"); item.Tag = itemTag;
Output.Write(itemTag.ToString(TagRenderMode.StartTag)); }
Output.Write(itemDisplayOutput);
Output.Write(itemTag.ToString(TagRenderMode.EndTag)); var itemOutput = Display(item).ToHtmlString();
if (!String.IsNullOrWhiteSpace(itemOutput)) {
itemTags.Add(itemTag);
itemOutputs.Add(itemOutput);
}
else {
count--;
}
++index; ++index;
} }
Output.Write(listTag.ToString(TagRenderMode.EndTag)); index = 0;
foreach(var itemOutput in itemOutputs) {
var itemTag = itemTags[index];
if (itemTag != null) {
if (index == 0)
itemTag.AddCssClass("first");
if (index == count - 1)
itemTag.AddCssClass("last");
Output.Write(itemTag.ToString(TagRenderMode.StartTag));
}
Output.Write(itemOutput);
if (itemTag != null) {
Output.Write(itemTag.ToString(TagRenderMode.EndTag));
}
++index;
}
if (listTag != null) {
Output.Write(listTag.ToString(TagRenderMode.EndTag));
}
} }
[Shape] [Shape]
@@ -718,5 +772,20 @@ namespace Orchard.Core.Shapes {
private string EncodeAlternateElement(string alternateElement) { private string EncodeAlternateElement(string alternateElement) {
return alternateElement.Replace("-", "__").Replace(".", "_"); return alternateElement.Replace("-", "__").Replace(".", "_");
} }
/// <summary>
/// Encode a value if it's a string, or render it if it's a Shape
/// </summary>
private IHtmlString EncodeOrDisplay(dynamic Value, dynamic Display, HtmlHelper Html) {
if (Value is IHtmlString) {
return Value;
}
if (Value is IShape) {
return Display(Value).ToString();
}
return Html.Raw(Html.Encode(Value.ToString()));
}
} }
} }

View File

@@ -1,5 +1,7 @@
@{ @{
// number of page number links to show, 0 means no link, 1 means only the current page, or more accepted.
Model.Quantity = 0; Model.Quantity = 0;
Model.PreviousText = T("Newer"); Model.PreviousText = T("Newer");
Model.NextText = T("Older"); Model.NextText = T("Older");
Model.Classes.Add("group"); Model.Classes.Add("group");