mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 03:25:23 +08:00
Further shapes work
Adding the ability to bind a method with a TextWriter Output parameter Bringing over work from UnorderedList Parameter bound with GetMember instead of array access to be compatible with base class properties --HG-- branch : theming
This commit is contained in:
@@ -1 +1 @@
|
||||
c6970f1f2d9c7a2bfdc0aeb43658dfcaf5688871 Clay
|
||||
57ebfff6441a6a246e81c1992996f06cd66c60ac Clay
|
||||
|
@@ -1,9 +1,34 @@
|
||||
using System.Web.Mvc;
|
||||
using Orchard.DisplayManagement;
|
||||
|
||||
namespace Orchard.Core.Dashboard.Controllers {
|
||||
public class AdminController : Controller {
|
||||
private readonly IShapeHelperFactory _shapeHelperFactory;
|
||||
|
||||
public AdminController(IShapeHelperFactory shapeHelperFactory) {
|
||||
_shapeHelperFactory = shapeHelperFactory;
|
||||
}
|
||||
|
||||
public ActionResult Index() {
|
||||
return View();
|
||||
var shape = _shapeHelperFactory.CreateHelper();
|
||||
var list = shape.List();
|
||||
var list2 = shape.List();
|
||||
|
||||
list.Id = "the-list";
|
||||
list.Classes.Add("foo");
|
||||
list.Attributes["onclick"] = "etc";
|
||||
list.ItemClasses.Add("yarg");
|
||||
|
||||
list.Add("one");
|
||||
list.Add("two");
|
||||
list.Add(list2);
|
||||
list.Add(shape.DumpShapeTable());
|
||||
list.Add("four");
|
||||
|
||||
list2.Add("three a");
|
||||
list2.Add("three b");
|
||||
|
||||
return View(list);
|
||||
}
|
||||
}
|
||||
}
|
@@ -4,3 +4,4 @@
|
||||
<p><%: T("This is the place where you can manage your web site, its appearance and its contents. Please take a moment to explore the different menu items on the left of the screen to familiarize yourself with the features of the application. For example, try to change the theme through the “Manage Themes” menu entry. You can also create new pages and manage existing ones through the “Manage Pages” menu entry or create blogs through “Manage Blogs”.") %></p>
|
||||
<p><%: T("Have fun!") %><br /><%: T("The Orchard Team") %></p>
|
||||
|
||||
<%:Display(Model) %>
|
||||
|
@@ -1,4 +1,8 @@
|
||||
using System.Web;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Mvc.Html;
|
||||
using Orchard.DisplayManagement;
|
||||
@@ -7,6 +11,8 @@ using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.UI;
|
||||
using Orchard.UI.Zones;
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
namespace Orchard.Core.Shapes {
|
||||
public class CoreShapes : IShapeDescriptorBindingStrategy {
|
||||
public Feature Feature { get; set; }
|
||||
@@ -21,6 +27,16 @@ namespace Orchard.Core.Shapes {
|
||||
// 'Zone' shapes are built on the Zone base class
|
||||
builder.Describe.Named("Zone").From(Feature.Descriptor)
|
||||
.OnCreating(creating => creating.BaseType = typeof(Zone));
|
||||
|
||||
// 'List' shapes start with several empty collections
|
||||
builder.Describe.Named("List").From(Feature.Descriptor)
|
||||
.OnCreated(created => {
|
||||
created.Shape.Tag = "ul";
|
||||
created.Shape.Classes = new List<string>();
|
||||
created.Shape.Attributes = new Dictionary<string, string>();
|
||||
created.Shape.ItemClasses = new List<string>();
|
||||
created.Shape.ItemAttributes = new Dictionary<string, string>();
|
||||
});
|
||||
}
|
||||
|
||||
static object DetermineModel(HtmlHelper Html, object Model) {
|
||||
@@ -28,6 +44,53 @@ namespace Orchard.Core.Shapes {
|
||||
return isNull ? Html.ViewData.Model : Model;
|
||||
}
|
||||
|
||||
static TagBuilder GetTagBuilder(string tagName, string id, IEnumerable<string> classes, IDictionary<string, string> attributes) {
|
||||
var tagBuilder = new TagBuilder(tagName);
|
||||
tagBuilder.MergeAttributes(attributes, false);
|
||||
foreach (var cssClass in classes ?? Enumerable.Empty<string>())
|
||||
tagBuilder.AddCssClass(cssClass);
|
||||
if (id != null)
|
||||
tagBuilder.GenerateId(id);
|
||||
return tagBuilder;
|
||||
}
|
||||
|
||||
[Shape]
|
||||
public void List(
|
||||
dynamic Display,
|
||||
TextWriter Output,
|
||||
IEnumerable<dynamic> Items,
|
||||
string Tag,
|
||||
string Id,
|
||||
IEnumerable<string> Classes,
|
||||
IDictionary<string, string> Attributes,
|
||||
IEnumerable<string> ItemClasses,
|
||||
IDictionary<string, string> ItemAttributes) {
|
||||
|
||||
var listTagName = string.IsNullOrEmpty(Tag) ? "ul" : Tag;
|
||||
const string itemTagName = "li";
|
||||
|
||||
var listTag = GetTagBuilder(listTagName, Id, Classes, Attributes);
|
||||
Output.Write(listTag.ToString(TagRenderMode.StartTag));
|
||||
|
||||
if (Items != null) {
|
||||
var count = Items.Count();
|
||||
var index = 0;
|
||||
foreach (var item in Items) {
|
||||
var itemTag = GetTagBuilder(itemTagName, null, ItemClasses, ItemAttributes);
|
||||
if (index == 0)
|
||||
itemTag.AddCssClass("first");
|
||||
if (index == count - 1)
|
||||
itemTag.AddCssClass("last");
|
||||
Output.Write(itemTag.ToString(TagRenderMode.StartTag));
|
||||
Output.Write(Display(item));
|
||||
Output.Write(itemTag.ToString(TagRenderMode.EndTag));
|
||||
++index;
|
||||
}
|
||||
}
|
||||
Output.Write(listTag.ToString(TagRenderMode.EndTag));
|
||||
}
|
||||
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Partial(HtmlHelper Html, string TemplateName, object Model) {
|
||||
return Html.Partial(TemplateName, DetermineModel(Html, Model));
|
||||
@@ -42,5 +105,6 @@ namespace Orchard.Core.Shapes {
|
||||
public IHtmlString EditorTemplate(HtmlHelper Html, string TemplateName, object Model, string Prefix) {
|
||||
return Html.Partial(TemplateName, DetermineModel(Html, Model));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -87,7 +87,6 @@
|
||||
<Content Include="ScaffoldingTemplates\DataMigration.txt" />
|
||||
<Compile Include="Services\ScaffoldingCommandInterpreter.cs" />
|
||||
<Compile Include="Settings\DevToolsSettings.cs" />
|
||||
<Compile Include="Shapes.cs" />
|
||||
<Compile Include="ViewModels\CommandsExecuteViewModel.cs" />
|
||||
<Compile Include="ViewModels\ContentIndexViewModel.cs" />
|
||||
<Compile Include="ViewModels\ContentDetailsViewModel.cs" />
|
||||
|
@@ -1,53 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.DisplayManagement;
|
||||
|
||||
namespace Orchard.DevTools {
|
||||
public class Shapes : IDependency {
|
||||
[Shape]
|
||||
public IHtmlString Title(dynamic text) {
|
||||
return new HtmlString("<h2>" + text + "</h2>");
|
||||
}
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Explosion(int? Height, int? Width) {
|
||||
|
||||
return new HtmlString(string.Format("<span>Boom {0}x{1}</span>", Height, Width));
|
||||
}
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Page(dynamic Display, dynamic Shape) {
|
||||
return Display(Shape.Sidebar, Shape.Messages);
|
||||
}
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Zone(dynamic Display, dynamic Shape) {
|
||||
var tag = new TagBuilder("div");
|
||||
tag.GenerateId("zone-" + Shape.Name);
|
||||
tag.AddCssClass("zone-" + Shape.Name);
|
||||
tag.AddCssClass("zone");
|
||||
|
||||
IEnumerable<IHtmlString> all = DisplayAll(Display, Shape);
|
||||
tag.InnerHtml = Combine(all.ToArray()).ToString();
|
||||
|
||||
return new HtmlString(tag.ToString());
|
||||
}
|
||||
|
||||
[Shape]
|
||||
public IHtmlString Message(dynamic Display, object Content, string Severity) {
|
||||
return Display(new HtmlString("<p class=\"message\">"), Severity ?? "Neutral", ": ", Content, new HtmlString("</p>"));
|
||||
}
|
||||
|
||||
static IHtmlString Combine(IEnumerable<IHtmlString> contents) {
|
||||
return new HtmlString(contents.Aggregate("", (a, b) => a + b));
|
||||
}
|
||||
|
||||
static IEnumerable<IHtmlString> DisplayAll(dynamic Display, dynamic Shape) {
|
||||
foreach (var item in Shape) {
|
||||
yield return Display(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -19,6 +19,7 @@ using Orchard.DisplayManagement.Implementation;
|
||||
using Orchard.DisplayManagement.Shapes;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Mvc;
|
||||
using Orchard.Mvc.Filters;
|
||||
@@ -37,6 +38,8 @@ using Orchard.UI.Zones;
|
||||
|
||||
namespace Orchard.Setup {
|
||||
public class SetupMode : Module {
|
||||
public Feature Feature { get; set; }
|
||||
|
||||
protected override void Load(ContainerBuilder builder) {
|
||||
|
||||
// standard services needed in setup mode
|
||||
@@ -77,7 +80,7 @@ namespace Orchard.Setup {
|
||||
builder.RegisterType<ConfiguredEnginesCache>().As<IConfiguredEnginesCache>();
|
||||
builder.RegisterType<PageWorkContext>().As<IWorkContextStateProvider>();
|
||||
|
||||
builder.RegisterType<CoreShapes>().As<IShapeDescriptorBindingStrategy>();
|
||||
builder.RegisterType<CoreShapes>().As<IShapeDescriptorBindingStrategy>().WithProperty("Feature", Feature);
|
||||
builder.RegisterType<ShapeTemplateBindingStrategy>().As<IShapeDescriptorBindingStrategy>();
|
||||
builder.RegisterType<BasicShapeTemplateHarvester>().As<IShapeTemplateHarvester>();
|
||||
}
|
||||
|
@@ -53,6 +53,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClaySharp", "..\Clay\src\Cl
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClaySharp.Tests", "..\Clay\src\ClaySharp.Tests\ClaySharp.Tests.csproj", "{10369238-A590-48BF-8D3E-E83EB6F0C931}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Notes", "_Notes", "{8A49DB66-40B2-4B6A-BFF0-D4839A240D00}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Shapes.txt = Shapes.txt
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
CodeCoverage|Any CPU = CodeCoverage|Any CPU
|
||||
|
@@ -1,9 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
@@ -12,6 +14,7 @@ using Autofac.Core;
|
||||
using ClaySharp.Implementation;
|
||||
using Microsoft.CSharp.RuntimeBinder;
|
||||
using Orchard.DisplayManagement.Implementation;
|
||||
using Orchard.DisplayManagement.Shapes;
|
||||
|
||||
namespace Orchard.DisplayManagement.Descriptors.ShapeAttributeStrategy {
|
||||
public class ShapeAttributeBindingStrategy : IShapeDescriptorBindingStrategy {
|
||||
@@ -55,27 +58,30 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeAttributeStrategy {
|
||||
|
||||
|
||||
private IHtmlString PerformInvoke(DisplayContext displayContext, MethodInfo methodInfo, object serviceInstance) {
|
||||
var output = new StringWriter();
|
||||
var arguments = methodInfo.GetParameters()
|
||||
.Select(parameter => BindParameter(displayContext, parameter));
|
||||
.Select(parameter => BindParameter(displayContext, parameter, output));
|
||||
|
||||
return CoerceHtmlString(methodInfo.Invoke(serviceInstance, arguments.ToArray()));
|
||||
var returnValue = methodInfo.Invoke(serviceInstance, arguments.ToArray());
|
||||
if (methodInfo.ReturnType != typeof(void)) {
|
||||
output.Write(returnValue);
|
||||
}
|
||||
return CoerceHtmlString(output);
|
||||
}
|
||||
|
||||
private static IHtmlString CoerceHtmlString(object invoke) {
|
||||
return invoke as IHtmlString ?? (invoke != null ? new HtmlString(invoke.ToString()) : null);
|
||||
}
|
||||
|
||||
private object BindParameter(DisplayContext displayContext, ParameterInfo parameter) {
|
||||
private object BindParameter(DisplayContext displayContext, ParameterInfo parameter, TextWriter output) {
|
||||
if (parameter.Name == "Shape")
|
||||
return displayContext.Value;
|
||||
|
||||
if (parameter.Name == "Display")
|
||||
return displayContext.Display;
|
||||
|
||||
if (parameter.Name == "Attributes") {
|
||||
var attributes = new RouteValueDictionary(((dynamic)(displayContext.Value))[parameter.Name]);
|
||||
return Arguments.From(attributes.Values, attributes.Keys);
|
||||
}
|
||||
if (parameter.Name == "Output" && parameter.ParameterType == typeof(TextWriter))
|
||||
return output;
|
||||
|
||||
// meh--
|
||||
if (parameter.Name == "Html") {
|
||||
@@ -85,11 +91,31 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeAttributeStrategy {
|
||||
_routeCollection);
|
||||
}
|
||||
|
||||
var result = ((dynamic)(displayContext.Value))[parameter.Name];
|
||||
var getter = _getters.GetOrAdd(parameter.Name, n =>
|
||||
CallSite<Func<CallSite, object, dynamic>>.Create(
|
||||
Microsoft.CSharp.RuntimeBinder.Binder.GetMember(
|
||||
CSharpBinderFlags.None, n, null, new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) })));
|
||||
|
||||
var result = getter.Target(getter, displayContext.Value);
|
||||
|
||||
//var result = ((dynamic)(displayContext.Value))[parameter.Name];
|
||||
if (result == null)
|
||||
return null;
|
||||
|
||||
//if (parameter.Name == "Attributes") {
|
||||
// var attributes = new RouteValueDictionary(result);
|
||||
// return Arguments.From(attributes.Values, attributes.Keys);
|
||||
//}
|
||||
|
||||
var converter = _converters.GetOrAdd(parameter.ParameterType, CompileConverter);
|
||||
return converter.Invoke((object)result);
|
||||
var argument = converter.Invoke((object)result);
|
||||
return argument;
|
||||
}
|
||||
|
||||
|
||||
static readonly ConcurrentDictionary<string, CallSite<Func<CallSite, object, dynamic>>> _getters =
|
||||
new ConcurrentDictionary<string, CallSite<Func<CallSite, object, dynamic>>>();
|
||||
|
||||
static readonly ConcurrentDictionary<Type, Func<object, object>> _converters =
|
||||
new ConcurrentDictionary<Type, Func<object, object>>();
|
||||
|
||||
|
@@ -17,7 +17,7 @@ namespace Orchard.DisplayManagement.Shapes {
|
||||
|
||||
public virtual Shape Add(object item, string position) {
|
||||
try {
|
||||
((dynamic) item).Metadata.Position = position;
|
||||
((dynamic)item).Metadata.Position = position;
|
||||
}
|
||||
catch {
|
||||
// need to implemented positioned wrapper for non-shape objects
|
||||
@@ -29,5 +29,9 @@ namespace Orchard.DisplayManagement.Shapes {
|
||||
public virtual IEnumerator GetEnumerator() {
|
||||
return _items.GetEnumerator();
|
||||
}
|
||||
|
||||
public virtual IEnumerable<dynamic> Items {
|
||||
get { return _items; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -39,7 +39,7 @@ namespace Orchard.UI.Navigation {
|
||||
.Text(menuItem.Text)
|
||||
.Href(menuItem.Href)
|
||||
.RouteValues(menuItem.RouteValues)
|
||||
.Object(menuItem);
|
||||
.Item(menuItem);
|
||||
|
||||
if (menuItem.Items != null && menuItem.Items.Any()) {
|
||||
PopulateMenu(shape, menuItemShape, menuItem.Items);
|
||||
|
91
src/Shapes.txt
Normal file
91
src/Shapes.txt
Normal file
@@ -0,0 +1,91 @@
|
||||
|
||||
==context==
|
||||
|
||||
WorkContext.Page == Layout shape
|
||||
|
||||
|
||||
==shapes==
|
||||
|
||||
.Id
|
||||
.Classes
|
||||
.Attributes
|
||||
|
||||
|
||||
Document [:Layout]
|
||||
|
||||
Layout
|
||||
- Zones (meta-property)
|
||||
- Title
|
||||
|
||||
|
||||
Zone
|
||||
-ZoneName
|
||||
|
||||
Menu
|
||||
-MenuName
|
||||
|
||||
MenuItem
|
||||
-Text
|
||||
-Href
|
||||
-RouteValues
|
||||
-Item
|
||||
|
||||
Menu
|
||||
MenuItem
|
||||
|
||||
List: ul|ol + li*
|
||||
-Items (meta-property, bound to shape children or passed in)
|
||||
|
||||
Pager
|
||||
-CurrentPage
|
||||
-RouteValues
|
||||
-Count
|
||||
?PageSize ?? 1
|
||||
|
||||
Shape.Pager(CurrentPage:page, PageSize:10, ItemCount:53)
|
||||
Shape.Pager(CurrentPage:page, PageCount:6)
|
||||
Shape.Pager(CurrentPage:page)
|
||||
|
||||
x
|
||||
y
|
||||
z
|
||||
|
||||
|
||||
List
|
||||
x
|
||||
y
|
||||
z
|
||||
|
||||
Items_Content
|
||||
Items_Content__BlogPost
|
||||
Items_Content__Page
|
||||
Items_Content__Product
|
||||
|
||||
Parts/Content
|
||||
|
||||
Fields/Content
|
||||
|
||||
|
||||
.Items_Content()
|
||||
.Items_Widget()
|
||||
.Items_User()
|
||||
|
||||
==template discovery strategy==
|
||||
Items/Content.cshtml -> "Items_Content"
|
||||
Items/Content-Page.cshtml -> "Items_Content__Page"
|
||||
Items/Content-45.cshtml -> "Items_Content__45"
|
||||
Items/Page.cshtml -> "Items_Content__Page"
|
||||
Items/BlogPost.cshtml -> "Items_Content__BlogPost"
|
||||
|
||||
Widgets-TwitterThing.cshtml -> "Widget__TwitterThing"
|
||||
|
||||
Items/User.cshtml -> "Items_User"
|
||||
|
||||
Parts/Yarg -> "Parts_Yarg"
|
||||
Parts/Yarg-BlogPost -> "Parts_Yarg__BlogPost"
|
||||
|
||||
==template discovery strategy==
|
||||
|
||||
==templates==
|
||||
Header
|
||||
Footer
|
Reference in New Issue
Block a user