Merge with clayless

--HG--
branch : 1.x
This commit is contained in:
Sebastien Ros 2013-02-04 10:51:21 -08:00
commit fca554ddc9
45 changed files with 1031 additions and 568 deletions

Binary file not shown.

Binary file not shown.

View File

@ -59,9 +59,6 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\autofac\Autofac.dll</HintPath>
</Reference>
<Reference Include="ClaySharp">
<HintPath>..\..\lib\claysharp\ClaySharp.dll</HintPath>
</Reference>
<Reference Include="FluentNHibernate, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8aa435e3cb308880, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\nhibernate\FluentNHibernate.dll</HintPath>

View File

@ -62,9 +62,6 @@
<Reference Include="Castle.Core">
<HintPath>..\..\lib\Castle Windsor 2.0\bin\Castle.Core.dll</HintPath>
</Reference>
<Reference Include="ClaySharp">
<HintPath>..\..\lib\claysharp\ClaySharp.dll</HintPath>
</Reference>
<Reference Include="FluentNHibernate, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8aa435e3cb308880, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\nhibernate\FluentNHibernate.dll</HintPath>

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Autofac;
using ClaySharp;
using NUnit.Framework;
using Orchard.Scripting.Dlr.Services;
using Path = Bleroy.FluentPath.Path;
@ -83,22 +82,6 @@ namespace Orchard.Tests.Modules.Scripting.Dlr {
Assert.That(_scriptingManager.ExecuteExpression("f / 4"), Is.EqualTo(8));
}
[Test]
public void CanDeclareCallbackOnGlobalMethod() {
_scriptingManager.SetVariable("x", new Clay(new ReturnMethodNameLengthBehavior()));
Assert.That(_scriptingManager.ExecuteExpression("3 + x.foo()"), Is.EqualTo(6));
}
public class ReturnMethodNameLengthBehavior : ClayBehavior {
public override object InvokeMemberMissing(Func<object> proceed, object self, string name, INamedEnumerable<object> args) {
Trace.WriteLine("Returning length of " + name);
return name.Length;
}
}
[Test]
public void CanDeclareCallbackOnInstanceEvalWithFile() {
var targetPath = _tempFolderName.Combine("CallbackOnInstanceEval.rb");

View File

@ -1,8 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Web.Routing;
using ClaySharp;
using ClaySharp.Implementation;
using Orchard.DisplayManagement;
namespace Orchard.Tests.DisplayManagement {
public static class ArgsUtility {

View File

@ -0,0 +1,61 @@
using NUnit.Framework;
using Orchard.DisplayManagement.Shapes;
namespace Orchard.Tests.DisplayManagement {
[TestFixture]
public class CompositeTests {
[Test]
public void CompositesShouldNotOverrideExistingMembers() {
var composite = new Animal {Color = "Pink"};
Assert.That(composite.Color, Is.EqualTo("Pink"));
}
[Test]
public void CompositesShouldNotOverrideExistingMembersWhenUsedAsDynamic() {
dynamic composite = new Animal();
composite.Color = "Pink";
Assert.That(composite.Color, Is.EqualTo("Pink"));
}
[Test]
public void CompositesShouldAccessUnknownProperties() {
dynamic composite = new Animal();
composite.Fake = 42;
Assert.That(composite.Fake, Is.EqualTo(42));
}
[Test]
public void CompositesShouldAccessUnknownPropertiesByIndex() {
dynamic composite = new Animal();
composite["Fake"] = 42;
Assert.That(composite["Fake"], Is.EqualTo(42));
}
[Test]
public void CompositesShouldAccessKnownPropertiesByIndex() {
dynamic composite = new Animal();
composite["Pink"] = "Pink";
Assert.That(composite["Pink"], Is.EqualTo("Pink"));
}
[Test]
public void ChainProperties() {
dynamic foo = new Animal();
foo.Bar("bar");
Assert.That(foo.Bar, Is.EqualTo("bar"));
Assert.That(foo.Bar == null, Is.False);
}
}
public class Animal : Composite {
public string Kind { get; set; }
public string Color { get; set; }
}
}

View File

@ -37,7 +37,43 @@ namespace Orchard.Tests.DisplayManagement {
[Test]
public void CreateShapeWithNamedArguments() {
var factory = _container.Resolve<IShapeFactory>();
var foo = factory.Create("Foo", ArgsUtility.Named(new { one = 1, two = "dos" }));
dynamic foo = factory.Create("Foo", ArgsUtility.Named(new { one = 1, two = "dos" }));
Assert.That(foo.one, Is.EqualTo(1));
Assert.That(foo.two, Is.EqualTo("dos"));
}
[Test]
public void CallSyntax() {
dynamic factory = _container.Resolve<IShapeFactory>();
var foo = factory.Foo();
ShapeMetadata metadata = foo.Metadata;
Assert.That(metadata.Type, Is.EqualTo("Foo"));
}
[Test]
public void CallInitializer() {
dynamic factory = _container.Resolve<IShapeFactory>();
var bar = new {One = 1, Two = "two"};
var foo = factory.Foo(bar);
Assert.That(foo.One, Is.EqualTo(1));
Assert.That(foo.Two, Is.EqualTo("two"));
}
[Test]
public void CallInitializerWithBaseType() {
dynamic factory = _container.Resolve<IShapeFactory>();
var bar = new { One = 1, Two = "two" };
var foo = factory.Foo(typeof(MyShape), bar);
Assert.That(foo, Is.InstanceOf<MyShape>());
Assert.That(foo.One, Is.EqualTo(1));
Assert.That(foo.Two, Is.EqualTo("two"));
}
public class MyShape : Shape {
public string Kind { get; set; }
}
}
}

View File

@ -0,0 +1,88 @@
using System;
using NUnit.Framework;
using Orchard.DisplayManagement.Shapes;
using Orchard.UI.Zones;
namespace Orchard.Tests.DisplayManagement {
[TestFixture]
public class ZoneHoldingTests {
[Test]
public void ZonesShouldReturn() {
Func<dynamic> factory = () => new Shape();
var foo = new ZoneHolding(factory);
Assert.That(foo.Zones, Is.InstanceOf<Zones>());
}
[Test]
public void MemberShouldCreateAZone() {
Func<dynamic> factory = () => new Shape();
dynamic foo = new ZoneHolding(factory);
Assert.That(foo.Header, Is.InstanceOf<ZoneOnDemand>());
}
[Test]
public void IndexShouldCreateAZone() {
Func<dynamic> factory = () => new Shape();
dynamic foo = new ZoneHolding(factory);
Assert.That(foo.Zones["Header"], Is.InstanceOf<ZoneOnDemand>());
}
[Test]
public void ZonesMemberShouldCreateAZone() {
Func<dynamic> factory = () => new Shape();
dynamic foo = new ZoneHolding(factory);
Assert.That(foo.Zones.Header, Is.InstanceOf<ZoneOnDemand>());
}
[Test]
public void ZonesShouldBeUnique() {
Func<dynamic> factory = () => new Shape();
dynamic foo = new ZoneHolding(factory);
var header = foo.Header;
Assert.That(foo.Zones.Header, Is.EqualTo(header));
Assert.That(foo.Zones["Header"], Is.EqualTo(header));
Assert.That(foo.Header, Is.EqualTo(header));
}
[Test]
public void EmptyZonesShouldBeNull() {
Func<dynamic> factory = () => new Shape();
dynamic foo = new ZoneHolding(factory);
Assert.That(foo.Header == 1, Is.False);
Assert.That(foo.Header != 1, Is.True);
dynamic header = foo.Header;
Assert.That(header == null, Is.True);
Assert.That(header != null, Is.False);
Assert.That(header == Nil.Instance, Is.True);
Assert.That(header != Nil.Instance, Is.False);
}
[Test]
public void NoneEmptyZonesShouldBeNull() {
Func<dynamic> factory = () => new Shape();
dynamic foo = new ZoneHolding(factory);
foo.Header.Add("blah");
Assert.That(foo.Header == null, Is.False);
Assert.That(foo.Header != null, Is.True);
Assert.That(foo.Header == Nil.Instance, Is.False);
Assert.That(foo.Header != Nil.Instance, Is.True);
}
}
}

View File

@ -71,10 +71,6 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\Castle Windsor 2.0\bin\Castle.DynamicProxy2.dll</HintPath>
</Reference>
<Reference Include="ClaySharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\claysharp\ClaySharp.dll</HintPath>
</Reference>
<Reference Include="FluentNHibernate, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8aa435e3cb308880, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\nhibernate\FluentNHibernate.dll</HintPath>
@ -220,6 +216,8 @@
<Compile Include="Data\Bags\SettingsTests.cs" />
<Compile Include="Data\StubLocator.cs" />
<Compile Include="DisplayManagement\ArgsUtility.cs" />
<Compile Include="DisplayManagement\CompositeTests.cs" />
<Compile Include="DisplayManagement\ZoneHoldingTests.cs" />
<Compile Include="DisplayManagement\DefaultDisplayManagerTests.cs" />
<Compile Include="ContainerTestBase.cs" />
<Compile Include="DisplayManagement\Descriptors\BasicShapeTemplateHarvesterTests.cs" />

View File

@ -2,107 +2,98 @@
using System.Collections.Generic;
using System.Linq;
using Autofac;
using ClaySharp;
using NUnit.Framework;
using Orchard.Core.Shapes;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation;
using Orchard.DisplayManagement.Shapes;
using Orchard.Environment;
using Orchard.Mvc;
using Orchard.Tests.DisplayManagement;
using Orchard.UI.Zones;
namespace Orchard.Tests.UI {
[TestFixture]
public class ShapeTests : ContainerTestBase {
private WorkContext _workContext;
dynamic _layout;
protected override void Register(ContainerBuilder builder) {
builder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>();
builder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>();
var defaultShapeTable = new ShapeTable {
Descriptors = new Dictionary<string, ShapeDescriptor>(StringComparer.OrdinalIgnoreCase),
Bindings = new Dictionary<string, ShapeBinding>(StringComparer.OrdinalIgnoreCase)
};
builder.Register(ctx => defaultShapeTable);
builder.RegisterType<DefaultDisplayManagerTests.TestWorkContextAccessor>().As<IWorkContextAccessor>();
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
builder.RegisterType<LayoutWorkContext>().As<IWorkContextStateProvider>();
//builder.RegisterType<CoreShapes>().As<IShapeTableProvider>();
builder.RegisterType<NumberIsAlwaysFortyTwo>().As<IShapeFactoryEvents>();
throw new NotImplementedException("this test fixture needs to move to modules tests now");
builder.RegisterType<ShapeTableLocator>().As<IShapeTableLocator>();
builder.RegisterType<DefaultDisplayManager>().As<IDisplayManager>();
builder.RegisterType<DefaultDisplayManagerTests.TestShapeTableManager>().As<IShapeTableManager>();
builder.RegisterType<CoreShapes>().As<IShapeTableProvider>();
}
protected override void Resolve(ILifetimeScope container) {
_workContext = container.Resolve<IWorkContextAccessor>().CreateWorkContextScope().WorkContext;
var shapeFactory = _container.Resolve<IShapeFactory>();
_layout = new ZoneHolding(() => shapeFactory.Create("Zone"));
}
[Test, Ignore("implementation pending")]
public void WorkContextPageIsLayoutShape() {
var layout = _workContext.Layout;
ShapeMetadata pageMetadata = layout.Metadata;
Assert.That(pageMetadata.Type, Is.EqualTo("Layout"));
Assert.That(layout.Metadata.Type, Is.EqualTo("Layout"));
}
[Test, Ignore("implementation pending")]
[Test]
public void PagePropertiesAreNil() {
var layout = _workContext.Layout;
var pageFoo = layout.Foo;
var pageFoo = _layout.Foo;
Assert.That(pageFoo == null);
}
[Test, Ignore("implementation pending")]
[Test]
public void PageZonesPropertyIsNotNil() {
var layout = _workContext.Layout;
var pageZones = layout.Zones;
var pageZones = _layout.Zones;
Assert.That(pageZones != null);
Assert.That(pageZones.Foo == null);
}
[Test, Ignore("implementation pending")]
[Test]
public void AddingToZonePropertyMakesItExist() {
var layout = _workContext.Layout;
Assert.That(layout.Zones.Foo == null);
Assert.That(_layout.Zones.Foo == null);
var pageZonesFoo = layout.Zones.Foo;
var pageZonesFoo = _layout.Zones.Foo;
pageZonesFoo.Add("hello");
Assert.That(layout.Zones.Foo != null);
Assert.That(layout.Foo != null);
Assert.That(layout.Foo.Metadata.Type, Is.EqualTo("Zone"));
Assert.That(_layout.Zones.Foo != null);
Assert.That(_layout.Foo != null);
Assert.That(_layout.Foo.Metadata.Type, Is.EqualTo("Zone"));
}
[Test, Ignore("implementation pending")]
[Test]
public void AddingToZoneIndexedMakesItExist() {
var layout = _workContext.Layout;
Assert.That(layout.Zones["Foo"] == null);
Assert.That(_layout.Zones["Foo"] == null);
var pageZonesFoo = layout.Zones["Foo"];
var pageZonesFoo = _layout.Zones["Foo"];
pageZonesFoo.Add("hello");
Assert.That(layout.Zones["Foo"] != null);
Assert.That(layout["Foo"] != null);
Assert.That(layout["Foo"].Metadata.Type, Is.EqualTo("Zone"));
Assert.That(_layout.Zones["Foo"] != null);
Assert.That(_layout["Foo"] != null);
Assert.That(_layout["Foo"].Metadata.Type, Is.EqualTo("Zone"));
}
[Test, Ignore("implementation pending")]
[Test]
public void CallingAddOnNilPropertyMakesItBecomeZone() {
var layout = _workContext.Layout;
Assert.That(layout.Foo == null);
Assert.That(_layout.Foo == null);
layout.Foo.Add("hello");
_layout.Foo.Add("hello");
Assert.That(layout.Foo != null);
Assert.That(layout.Foo.Metadata.Type, Is.EqualTo("Zone"));
Assert.That(_layout.Foo != null);
Assert.That(_layout.Foo.Metadata.Type, Is.EqualTo("Zone"));
}
[Test, Ignore("implementation pending")]
[Test]
public void ZoneContentsAreEnumerable() {
var layout = _workContext.Layout;
Assert.That(layout.Foo == null);
Assert.That(_layout.Foo == null);
layout.Foo.Add("hello");
layout.Foo.Add("world");
_layout.Foo.Add("hello");
_layout.Foo.Add("world");
var list = new List<object>();
foreach (var item in layout.Foo) {
foreach (var item in _layout.Foo) {
list.Add(item);
}
@ -111,27 +102,38 @@ namespace Orchard.Tests.UI {
Assert.That(list.Last(), Is.EqualTo("world"));
}
[Test]
public void ZoneContentsCastBeConvertedToEnunerableOfObject() {
Assert.That(_layout.Foo == null);
class NumberIsAlwaysFortyTwo : ShapeFactoryEvents {
public override void Creating(ShapeCreatingContext context) {
context.Behaviors.Add(new Behavior());
}
_layout.Foo.Add("hello");
_layout.Foo.Add("world");
class Behavior : ClayBehavior {
public override object GetMember(Func<object> proceed, object self, string name) {
return name == "Number" ? 42 : proceed();
}
}
IEnumerable<object> list = _layout.Foo;
Assert.That(list.Count(), Is.EqualTo(2));
Assert.That(list.First(), Is.EqualTo("hello"));
Assert.That(list.Last(), Is.EqualTo("world"));
var first = ((IEnumerable<object>)_layout.Foo).FirstOrDefault();
Assert.That(first, Is.EqualTo("hello"));
}
[Test, Ignore("implementation pending")]
public void NumberIsFortyTwo() {
var layout = _workContext.Layout;
Assert.That(layout.Number, Is.EqualTo(42));
Assert.That(layout.Foo.Number == null);
layout.Foo.Add("yarg");
Assert.That(layout.Foo.Number, Is.EqualTo(42));
[Test]
public void ZoneContentsCastBeConvertedToEnunerableOfDynamics() {
Assert.That(_layout.Foo == null);
_layout.Foo.Add("hello");
_layout.Foo.Add("world");
IEnumerable<dynamic> list = _layout.Foo;
Assert.That(list.Count(), Is.EqualTo(2));
Assert.That(list.First(), Is.EqualTo("hello"));
Assert.That(list.Last(), Is.EqualTo("world"));
var first = ((IEnumerable<dynamic>) _layout.Foo).FirstOrDefault();
Assert.That(first, Is.EqualTo("hello"));
}
}
}

View File

@ -46,11 +46,6 @@
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="ClaySharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\claysharp\ClaySharp.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations">

View File

@ -48,7 +48,7 @@ namespace Orchard.Core.Shapes {
// and has an automatic zone creating behavior
builder.Describe("Layout")
.Configure(descriptor => descriptor.Wrappers.Add("Document"))
.OnCreating(creating => creating.Behaviors.Add(new ZoneHoldingBehavior(() => creating.New.Zone(), null)))
.OnCreating(creating => creating.Create = () => new ZoneHolding(() => creating.New.Zone()))
.OnCreated(created => {
var layout = created.Shape;
@ -68,7 +68,7 @@ namespace Orchard.Core.Shapes {
// They have class="zone zone-{name}"
// and the template can be specialized with "Zone-{Name}" base file name
builder.Describe("Zone")
.OnCreating(creating => creating.BaseType = typeof(Zone))
.OnCreating(creating => creating.Create = () => new Zone())
.OnDisplaying(displaying => {
var zone = displaying.Shape;
string zoneName = zone.ZoneName;

View File

@ -21,6 +21,10 @@
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>4.0</OldToolsVersion>
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -41,7 +45,6 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="ClaySharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;
using ClaySharp.Implementation;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Handlers;
@ -215,8 +214,9 @@ namespace Orchard.ContentTypes.Services {
}
private dynamic CreateItemShape(string actualShapeType) {
var zoneHoldingBehavior = new ZoneHoldingBehavior((Func<dynamic>)(() => _shapeFactory.Create("ContentZone", Arguments.Empty())), _workContextAccessor.GetContext().Layout);
return _shapeFactory.Create(actualShapeType, Arguments.Empty(), new[] { zoneHoldingBehavior });
var zoneHolding = new ZoneHolding(() => _shapeFactory.Create("ContentZone", Arguments.Empty()));
zoneHolding.Metadata.Type = actualShapeType;
return zoneHolding;
}
private void BindPlacement(BuildShapeContext context, string displayType, string stereotype) {

View File

@ -21,6 +21,10 @@
</UpgradeBackupLocation>
<TargetFrameworkProfile />
<UseIISExpress>false</UseIISExpress>
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -42,10 +46,6 @@
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="ClaySharp">
<HintPath>..\..\..\..\lib\claysharp\ClaySharp.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Data" />

View File

@ -550,7 +550,7 @@ jQuery(function ($) {
var text = shapeNode.type;
// add the hint to the tree node if available
if (shapeNode.hint != '') {
if (shapeNode.hint && shapeNode.hint != '') {
text += ' [' + shapeNode.hint + ']';
}

View File

@ -4,7 +4,6 @@ using System.Collections;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using ClaySharp;
using Orchard.ContentManagement;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Shapes;
@ -195,12 +194,19 @@ namespace Orchard.DesignerTools.Services {
}
private void DumpShape(IShape shape) {
var members = new Dictionary<string, object>();
((IClayBehaviorProvider) (dynamic) shape).Behavior.GetMembers(() => null, shape, members);
var value = shape as Shape;
foreach (var key in members.Keys.Where(key => !key.StartsWith("_"))) {
if (value == null) {
return;
}
foreach (DictionaryEntry entry in value.Properties) {
// ignore private members (added dynamically by the shape wrapper)
Dump(members[key], key);
if (entry.Key.ToString().StartsWith("_")) {
continue;
}
Dump(entry.Value, entry.Key.ToString());
}
}

View File

@ -46,9 +46,6 @@
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="ClaySharp">
<HintPath>..\..\..\..\lib\claysharp\ClaySharp.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Newtonsoft.Json">
<HintPath>..\..\..\..\lib\newtonsoft.json\Newtonsoft.Json.dll</HintPath>

View File

@ -26,8 +26,8 @@ namespace Orchard.Forms.Shapes {
builder.Describe("Input").Configure(descriptor => descriptor.Wrappers.Add("InputWrapper"));
builder.Describe("SelectList").Configure(descriptor => descriptor.Wrappers.Add("InputWrapper"));
builder.Describe("Textarea").Configure(descriptor => descriptor.Wrappers.Add("InputWrapper"));
builder.Describe("Form").OnCreating(ctx => ctx.Behaviors.Add(new PropertiesAreItems()));
builder.Describe("Fieldset").OnCreating(ctx => ctx.Behaviors.Add(new PropertiesAreItems()));
builder.Describe("Form").OnCreating(ctx => ctx.Create = () => new PropertiesAreItems());
builder.Describe("Fieldset").OnCreating(ctx => ctx.Create = () => new PropertiesAreItems());
}
[Shape]

View File

@ -1,26 +1,26 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using Orchard.DisplayManagement;
using ClaySharp;
using Orchard.DisplayManagement.Shapes;
namespace Orchard.Forms.Shapes {
public class PropertiesAreItems : ClayBehavior {
public override object SetMember(Func<object> proceed, dynamic self, string name, object value) {
Patch(self, name, value);
return proceed();
public class PropertiesAreItems : Composite {
public override bool TrySetMember(System.Dynamic.SetMemberBinder binder, object value) {
Patch(this, binder.Name, value);
return base.TrySetMember(binder, value);
}
public override object SetIndex(Func<object> proceed, dynamic self, IEnumerable<object> keys, object value) {
if (keys.Count() == 1 && keys.All(k => k is string))
Patch(self, System.Convert.ToString(keys.Single()), value);
return proceed();
public override bool TrySetIndex(System.Dynamic.SetIndexBinder binder, object[] indexes, object value) {
if (indexes.Count() == 1 && indexes.All(k => k is string))
Patch(this, System.Convert.ToString(indexes.Single()), value);
return base.TrySetIndex(binder, indexes, value);
}
public override object InvokeMember(Func<object> proceed, dynamic self, string name, INamedEnumerable<object> args) {
if (args.Count() == 1 && args.Named.Count() == 0)
Patch(self, name, args.Single());
return proceed();
public override bool TryInvokeMember(System.Dynamic.InvokeMemberBinder binder, object[] args, out object result) {
var arguments = Arguments.From(args, binder.CallInfo.ArgumentNames);
if (args.Count() == 1 && !arguments.Named.Any())
Patch(this, binder.Name, args.Single());
return base.TryInvokeMember(binder, args, out result);
}
readonly IDictionary<string, object> _assigned = new Dictionary<string, object>();

View File

@ -21,6 +21,10 @@
</UpgradeBackupLocation>
<TargetFrameworkProfile />
<UseIISExpress>false</UseIISExpress>
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -42,7 +46,6 @@
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="ClaySharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Data" />

View File

@ -50,9 +50,6 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\lib\autofac\Autofac.dll</HintPath>
</Reference>
<Reference Include="ClaySharp">
<HintPath>..\..\..\..\lib\claysharp\ClaySharp.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.ComponentModel.DataAnnotations">

View File

@ -30,7 +30,11 @@
: null;
IHtmlString sectionHeaderMarkup;
if (firstOfTheSecond != null && firstLevelMenuItem.LinkToFirstChild && (firstOfTheSecond.RouteValues != null || HasText(firstOfTheSecond.Url))) {
if (firstOfTheSecond != null
&& firstLevelMenuItem.LinkToFirstChild
&& (
firstOfTheSecond.RouteValues != null
|| HasText(firstOfTheSecond.Url))) {
sectionHeaderMarkup = HasText(itemId)
? Html.Link(sectionHeaderText, (string)firstOfTheSecond.Href, new { @class = itemClassName, id = itemId })
: Html.Link(sectionHeaderText, (string)firstOfTheSecond.Href, new { @class = itemClassName });
@ -72,7 +76,7 @@
<ul class="menuItems">
@foreach (var secondLevelMenuItem in secondLevelMenuItems.Where(menuItem => !menuItem.LocalNav)) {
string secondLevelTextHint = secondLevelMenuItem.Text.TextHint;
var firstOfTheThird = ((IEnumerable<dynamic>)secondLevelMenuItem).FirstOrDefault();
var firstOfTheThird = ((IEnumerable<dynamic>)secondLevelMenuItem.Items).FirstOrDefault();
var secondLevelItemClassName = HasText(secondLevelTextHint)
? "subnavicon-" + secondLevelTextHint.HtmlClassify()

View File

@ -10,36 +10,32 @@
<configuration>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<remove name="host" />
<remove name="pages" />
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<remove name="host"/>
<remove name="pages"/>
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false"/>
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false"/>
</sectionGroup>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" requirePermission="false" />
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" requirePermission="false"/>
</configSections>
<appSettings>
<add key="webpages:Enabled" value="false" />
<add key="log4net.Config" value="Config\log4net.config" />
<add key="webpages:Enabled" value="false"/>
<add key="log4net.Config" value="Config\log4net.config"/>
</appSettings>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<pages pageBaseType="Orchard.Mvc.ViewEngines.Razor.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages" />
<add namespace="System.Web.Mvc"/>
<add namespace="System.Web.Mvc.Ajax"/>
<add namespace="System.Web.Mvc.Html"/>
<add namespace="System.Web.Routing"/>
<add namespace="System.Web.WebPages"/>
<add namespace="System.Linq"/>
<add namespace="System.Collections.Generic"/>
<add namespace="Orchard.Mvc.Html"/>
</namespaces>
</pages>
</system.web.webPages.razor>
<!--
Set default transaction timeout to 30 minutes so that interactive debugging
is easier (default timeout is less than one minute)
@ -49,8 +45,7 @@
</system.transactions>
<system.web>
<!--<trust level="Medium" originUrl="" />-->
<httpRuntime requestValidationMode="2.0" />
<httpRuntime requestValidationMode="2.0"/>
<!--
Set compilation debug="true" to insert debugging
symbols into the compiled page. Because this
@ -58,7 +53,7 @@
during development.
-->
<compilation debug="false" targetFramework="4.0" batch="true" numRecompilesBeforeAppRestart="250" optimizeCompilations="true">
<buildProviders>
<buildProviders>
<add extension=".csproj" type="Orchard.Environment.Extensions.Compilers.CSharpExtensionBuildProviderShim"/>
</buildProviders>
<assemblies>
@ -66,24 +61,24 @@
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"/>
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"/>
<add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<remove assembly="System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<remove assembly="System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<remove assembly="System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<remove assembly="System.Web.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<remove assembly="System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<remove assembly="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<remove assembly="System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<remove assembly="System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<remove assembly="System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<remove assembly="System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<remove assembly="System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
<remove assembly="System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
<remove assembly="System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<remove assembly="System.Web.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
<remove assembly="System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<remove assembly="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
<remove assembly="System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
<remove assembly="System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<remove assembly="System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<remove assembly="System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<remove assembly="System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<remove assembly="System.ServiceModel.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<remove assembly="System.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<remove assembly="System.ServiceModel.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<remove assembly="System.WorkflowServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<remove assembly="System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<remove assembly="System.Data.DataSetExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<remove assembly="System.Web.ApplicationServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<remove assembly="System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<remove assembly="System.Data.DataSetExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<remove assembly="System.Web.ApplicationServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</assemblies>
</compilation>
<!--
@ -94,7 +89,6 @@
<authentication mode="Forms">
<forms loginUrl="~/Users/Account/AccessDenied" timeout="2880"/>
</authentication>
<!--
The <customErrors> section enables configuration
of what to do if/when an unhandled error occurs
@ -102,7 +96,7 @@
it enables developers to configure html error pages
to be displayed in place of a error stack trace.
-->
<customErrors mode="RemoteOnly" />
<customErrors mode="RemoteOnly"/>
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID">
<namespaces>
<add namespace="System.Web.Mvc"/>
@ -114,14 +108,11 @@
<add namespace="Orchard.Mvc.Html"/>
</namespaces>
</pages>
<httpHandlers>
<!-- see below -->
<clear />
<clear/>
<add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
</httpHandlers>
<httpModules>
<add name="WarmupHttpModule" type="Orchard.WarmupStarter.WarmupHttpModule, Orchard.WarmupStarter, Version=1.0.20, Culture=neutral"/>
</httpModules>
@ -131,10 +122,9 @@
Information Services 7.0. It is not necessary for previous version of IIS.
-->
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="true">
<remove name="WarmupHttpModule" />
<remove name="WarmupHttpModule"/>
<add name="WarmupHttpModule" type="Orchard.WarmupStarter.WarmupHttpModule, Orchard.WarmupStarter, Version=1.0.20, Culture=neutral"/>
</modules>
<handlers accessPolicy="Script">
@ -142,18 +132,16 @@
<clear/>
<!-- Return 404 for all requests via managed handler. The url routing handler will substitute the mvc request handler when routes match. -->
<add name="NotFound" path="*" verb="*" type="System.Web.HttpNotFoundHandler" preCondition="integratedMode" requireAccess="Script"/>
<!-- WebApi -->
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit"/>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit"/>
<remove name="ExtensionlessUrlHandler-Integrated-4.0"/>
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0"/>
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0"/>
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0"/>
</handlers>
<!-- Prevent IIS 7.0 from returning a custom 404/500 error page of its own -->
<httpErrors existingResponse="PassThrough" />
<httpErrors existingResponse="PassThrough"/>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
@ -162,42 +150,34 @@
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Razor" publicKeyToken="31bf3856ad364e35" />
<assemblyIdentity name="System.Web.Razor" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages.Deployment" publicKeyToken="31bf3856ad364e35" />
<assemblyIdentity name="System.Web.WebPages.Deployment" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages.Razor" publicKeyToken="31bf3856ad364e35" />
<assemblyIdentity name="System.Web.WebPages.Razor" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="NHibernate" publicKeyToken="aa95f207798dfdb4" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.3.1.4000" newVersion="3.3.1.4000" />
<assemblyIdentity name="NHibernate" publicKeyToken="aa95f207798dfdb4" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.3.1.4000" newVersion="3.3.1.4000"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Autofac" publicKeyToken="17863af14b0044da" />
<bindingRedirect oldVersion="2.2.0.0-2.6.3.862" newVersion="2.6.3.862" />
<assemblyIdentity name="Autofac" publicKeyToken="17863af14b0044da"/>
<bindingRedirect oldVersion="2.2.0.0-2.6.3.862" newVersion="2.6.3.862"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
</configuration>

View File

@ -2,15 +2,12 @@ using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using ClaySharp;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.Records;
namespace Orchard.ContentManagement {
public class ContentItem : IContent, IContentBehavior, IDynamicMetaObjectProvider {
public class ContentItem : DynamicObject, IContent {
public ContentItem() {
_behavior = new ClayBehaviorCollection(new[] { new ContentItemBehavior(this) });
_parts = new List<ContentPart>();
}
@ -45,14 +42,20 @@ namespace Orchard.ContentManagement {
_parts.Add(part);
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
private readonly IClayBehavior _behavior;
IClayBehavior IContentBehavior.Behavior {
get { return _behavior; }
}
DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
return new ClayMetaObject(this, parameter, ex => Expression.Property(Expression.Convert(ex, typeof(IContentBehavior)), "Behavior"));
}
var found = base.TryGetMember(binder, out result);
if (!found) {
foreach (var part in Parts) {
if (part.PartDefinition.Name == binder.Name) {
result = part;
return true;
}
}
return false;
}
return true;
}
}
}

View File

@ -1,21 +0,0 @@
using System;
using ClaySharp;
namespace Orchard.ContentManagement {
public class ContentItemBehavior : ClayBehavior {
private readonly IContent _content;
public ContentItemBehavior(IContent content) {
_content = content;
}
public override object GetMemberMissing(Func<object> proceed, object self, string name) {
var contentItem = _content.ContentItem;
foreach (var part in contentItem.Parts) {
if (part.PartDefinition.Name == name)
return part;
}
return base.GetMemberMissing(proceed, self, name);
}
}
}

View File

@ -2,19 +2,16 @@ using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using System.Web.Mvc;
using ClaySharp;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.Utilities;
using Orchard.UI;
namespace Orchard.ContentManagement {
public class ContentPart : IContent, IContentBehavior, IDynamicMetaObjectProvider {
public class ContentPart : DynamicObject, IContent {
private readonly IList<ContentField> _fields;
public ContentPart() {
_behavior = new ClayBehaviorCollection(new[] { new ContentPartBehavior(this) });
_fields = new List<ContentField>();
}
@ -29,14 +26,6 @@ namespace Orchard.ContentManagement {
}
}
private readonly IClayBehavior _behavior;
IClayBehavior IContentBehavior.Behavior {
get { return _behavior; }
}
DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
return new ClayMetaObject(this, parameter, ex => Expression.Property(Expression.Convert(ex, typeof(IContentBehavior)), "Behavior"));
}
/// <summary>
/// The ContentItem's identifier.
/// </summary>
@ -65,6 +54,28 @@ namespace Orchard.ContentManagement {
_fields.Add(field);
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
var found = base.TryGetMember(binder, out result);
if (!found) {
foreach (var part in ContentItem.Parts) {
if (part.PartDefinition.Name == binder.Name) {
result = part;
return true;
}
}
foreach (var field in Fields) {
if (field.PartFieldDefinition.Name == binder.Name) {
result = field;
return true;
}
}
return false;
}
return true;
}
}

View File

@ -1,20 +0,0 @@
using System;
namespace Orchard.ContentManagement {
public class ContentPartBehavior : ContentItemBehavior {
private readonly ContentPart _contentPart;
public ContentPartBehavior(ContentPart contentPart)
: base(contentPart) {
_contentPart = contentPart;
}
public override object GetMemberMissing(Func<object> proceed, object self, string name) {
foreach (var field in _contentPart.Fields) {
if (field.PartFieldDefinition.Name == name)
return field;
}
return base.GetMemberMissing(proceed, self, name);
}
}
}

View File

@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Web;
using System.Web.Routing;
using ClaySharp.Implementation;
using Orchard.ContentManagement.Handlers;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
@ -110,8 +109,7 @@ namespace Orchard.ContentManagement {
}
private dynamic CreateItemShape(string actualShapeType) {
var zoneHoldingBehavior = new ZoneHoldingBehavior((Func<dynamic>)(() => _shapeFactory.Create("ContentZone", Arguments.Empty())), _workContextAccessor.GetContext().Layout);
return _shapeFactory.Create(actualShapeType, Arguments.Empty(), new[] { zoneHoldingBehavior });
return _shapeFactory.Create(actualShapeType, Arguments.Empty(), () => new ZoneHolding(() => _shapeFactory.Create("ContentZone", Arguments.Empty())));
}
private void BindPlacement(BuildShapeContext context, string displayType, string stereotype) {

View File

@ -1,7 +0,0 @@
using ClaySharp;
namespace Orchard.ContentManagement {
public interface IContentBehavior {
IClayBehavior Behavior { get; }
}
}

View File

@ -0,0 +1,152 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Orchard.DisplayManagement {
public static class Arguments {
public static INamedEnumerable<T> FromT<T>(IEnumerable<T> arguments, IEnumerable<string> names) {
return new NamedEnumerable<T>(arguments, names);
}
public static INamedEnumerable<object> From(IEnumerable<object> arguments, IEnumerable<string> names) {
return new NamedEnumerable<object>(arguments, names);
}
class NamedEnumerable<T> : INamedEnumerable<T> {
readonly IEnumerable<T> _arguments;
readonly IEnumerable<string> _names;
public NamedEnumerable(IEnumerable<T> arguments, IEnumerable<string> names) {
if (arguments == null) {
throw new ArgumentNullException("arguments");
}
if (names == null) {
throw new ArgumentNullException("names");
}
if (arguments.Count() < names.Count()) {
throw new ArgumentException("arguments.Count() < names.Count()");
}
_arguments = arguments;
_names = names;
}
IEnumerator IEnumerable.GetEnumerator() {
return _arguments.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator() {
return _arguments.GetEnumerator();
}
IEnumerable<T> INamedEnumerable<T>.Positional {
get { return _arguments.Take(_arguments.Count() - _names.Count()); }
}
IDictionary<string, T> INamedEnumerable<T>.Named {
get { return new Named(_arguments, _names); }
}
class Named : IDictionary<string, T> {
private readonly IEnumerable<T> _arguments;
private readonly IEnumerable<string> _names;
private ICollection<T> _argumentsCollection;
private ICollection<string> _namesCollection;
public Named(IEnumerable<T> arguments, IEnumerable<string> names) {
_arguments = arguments.Skip(arguments.Count() - names.Count());
_names = names;
}
IEnumerable<KeyValuePair<string, T>> MakeEnumerable() {
return _arguments.Zip(_names, (arg, name) => new KeyValuePair<string, T>(name, arg));
}
IEnumerator<KeyValuePair<string, T>> IEnumerable<KeyValuePair<string, T>>.GetEnumerator() {
return MakeEnumerable().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return MakeEnumerable().GetEnumerator();
}
void ICollection<KeyValuePair<string, T>>.Add(KeyValuePair<string, T> item) {
throw new NotImplementedException();
}
void ICollection<KeyValuePair<string, T>>.Clear() {
throw new NotImplementedException();
}
bool ICollection<KeyValuePair<string, T>>.Contains(KeyValuePair<string, T> item) {
return MakeEnumerable().Contains(item);
}
void ICollection<KeyValuePair<string, T>>.CopyTo(KeyValuePair<string, T>[] array, int arrayIndex) {
throw new NotImplementedException();
}
bool ICollection<KeyValuePair<string, T>>.Remove(KeyValuePair<string, T> item) {
throw new NotImplementedException();
}
int ICollection<KeyValuePair<string, T>>.Count {
get { return _names.Count(); }
}
bool ICollection<KeyValuePair<string, T>>.IsReadOnly {
get { return true; }
}
bool IDictionary<string, T>.ContainsKey(string key) {
return _names.Contains(key);
}
void IDictionary<string, T>.Add(string key, T value) {
throw new NotImplementedException();
}
bool IDictionary<string, T>.Remove(string key) {
throw new NotImplementedException();
}
bool IDictionary<string, T>.TryGetValue(string key, out T value) {
var pair = MakeEnumerable().FirstOrDefault(kv => kv.Key == key);
// pair is a value type. in case of key-miss,
// will default to key=(string)null,value=(object)null
value = pair.Value;
return pair.Key != null;
}
//TBD
T IDictionary<string, T>.this[string key] {
get {
return MakeEnumerable()
.Where(kv => kv.Key == key)
.Select(kv => kv.Value)
.FirstOrDefault();
}
set { throw new NotImplementedException(); }
}
ICollection<string> IDictionary<string, T>.Keys {
get {
return _namesCollection = _namesCollection ?? _names as ICollection<string> ?? _names.ToArray();
}
}
ICollection<T> IDictionary<string, T>.Values {
get { return _argumentsCollection = _argumentsCollection ?? _arguments as ICollection<T> ?? _arguments.ToArray(); }
}
}
}
public static INamedEnumerable<object> Empty() {
return From(Enumerable.Empty<object>(), Enumerable.Empty<string>());
}
}
}

View File

@ -0,0 +1,8 @@
using System.Collections.Generic;
namespace Orchard.DisplayManagement {
public interface INamedEnumerable<T> : IEnumerable<T> {
IEnumerable<T> Positional { get; }
IDictionary<string, T> Named { get; }
}
}

View File

@ -1,6 +1,4 @@
using System.Collections.Generic;
using ClaySharp;
using ClaySharp.Implementation;
using System;
namespace Orchard.DisplayManagement {
/// <summary>
@ -9,7 +7,7 @@ namespace Orchard.DisplayManagement {
/// </summary>
public interface IShapeFactory : IDependency {
IShape Create(string shapeType, INamedEnumerable<object> parameters);
IShape Create(string shapeType, INamedEnumerable<object> parameters, IEnumerable<IClayBehavior> behaviors);
IShape Create(string shapeType, INamedEnumerable<object> parameters, Func<dynamic> createShape);
}
public static class ShapeFactoryExtensions {

View File

@ -1,35 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ClaySharp;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Shapes;
namespace Orchard.DisplayManagement.Implementation {
public class DefaultShapeFactory : Clay, IShapeFactory {
public class DefaultShapeFactory : Composite, IShapeFactory {
private readonly IEnumerable<Lazy<IShapeFactoryEvents>> _events;
private readonly Lazy<IShapeTableLocator> _shapeTableLocator;
public DefaultShapeFactory(
IEnumerable<Lazy<IShapeFactoryEvents>> events,
Lazy<IShapeTableLocator> shapeTableLocator) : base(new ShapeFactoryBehavior())
Lazy<IShapeTableLocator> shapeTableLocator)
{
_events = events;
_shapeTableLocator = shapeTableLocator;
}
class ShapeFactoryBehavior : ClayBehavior {
public override object InvokeMember(Func<object> proceed, object target, string name, INamedEnumerable<object> args) {
return ((DefaultShapeFactory)target).Create(name, args);
}
public override bool TryInvokeMember(System.Dynamic.InvokeMemberBinder binder, object[] args, out object result) {
result = Create(binder.Name, Arguments.From(args, binder.CallInfo.ArgumentNames));
return true;
}
public IShape Create(string shapeType, INamedEnumerable<object> parameters) {
return Create(shapeType, parameters, Enumerable.Empty<IClayBehavior>());
return Create(shapeType, parameters, () => new Shape());
}
public IShape Create(string shapeType, INamedEnumerable<object> parameters, IEnumerable<IClayBehavior> behaviors) {
public IShape Create(string shapeType, INamedEnumerable<object> parameters, Func<dynamic> createShape) {
var defaultShapeTable = _shapeTableLocator.Value.Lookup(null);
ShapeDescriptor shapeDescriptor;
defaultShapeTable.Descriptors.TryGetValue(shapeType, out shapeDescriptor);
@ -40,42 +38,20 @@ namespace Orchard.DisplayManagement.Implementation {
ShapeType = shapeType,
OnCreated = new List<Action<ShapeCreatedContext>>()
};
var positional = parameters.Positional;
creatingContext.BaseType = positional.Take(1).OfType<Type>().SingleOrDefault();
if (creatingContext.BaseType == null) {
IEnumerable<object> positional = parameters.Positional.ToList();
var baseType = positional.FirstOrDefault() as Type;
if (baseType == null) {
// default to common base class
creatingContext.BaseType = typeof(Shape);
creatingContext.Create = createShape ?? (() => new Shape());
}
else {
// consume the first argument
positional = positional.Skip(1);
}
if (creatingContext.BaseType == typeof(Array)) {
// array is a hint - not an intended base class
creatingContext.BaseType = typeof(Shape);
creatingContext.Behaviors = new List<IClayBehavior> {
new ClaySharp.Behaviors.InterfaceProxyBehavior(),
new ClaySharp.Behaviors.PropBehavior(),
new ClaySharp.Behaviors.ArrayBehavior(),
new ClaySharp.Behaviors.NilResultBehavior(),
};
}
else {
creatingContext.Behaviors = new List<IClayBehavior> {
new ClaySharp.Behaviors.InterfaceProxyBehavior(),
new ClaySharp.Behaviors.PropBehavior(),
new ClaySharp.Behaviors.NilResultBehavior(),
new Shape.ShapeBehavior(),
};
creatingContext.Create = () => Activator.CreateInstance(baseType);
}
if (behaviors != null && behaviors.Any()) {
// include behaviors passed in by caller, if any
creatingContext.Behaviors = creatingContext.Behaviors.Concat(behaviors).ToList();
}
// "creating" events may add behaviors and alter base type)
foreach (var ev in _events) {
ev.Value.Creating(creatingContext);
@ -90,10 +66,15 @@ namespace Orchard.DisplayManagement.Implementation {
var createdContext = new ShapeCreatedContext {
New = creatingContext.New,
ShapeType = creatingContext.ShapeType,
Shape = ClayActivator.CreateInstance(creatingContext.BaseType, creatingContext.Behaviors)
Shape = creatingContext.Create()
};
var shapeMetadata = new ShapeMetadata { Type = shapeType };
createdContext.Shape.Metadata = shapeMetadata;
if (!(createdContext.Shape is IShape)) {
throw new InvalidOperationException("Invalid base type for shape: " + createdContext.Shape.GetType().ToString());
}
ShapeMetadata shapeMetadata = createdContext.Shape.Metadata;
createdContext.Shape.Metadata.Type = shapeType;
if (shapeDescriptor != null)
shapeMetadata.Wrappers = shapeMetadata.Wrappers.Concat(shapeDescriptor.Wrappers).ToList();

View File

@ -1,17 +1,12 @@
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ClaySharp;
namespace Orchard.DisplayManagement.Implementation {
/// <summary>
/// Refactor: I this doesn't really need to exist, does it?
/// It can all be an aspect of a display helper behavior implementation...
/// Or should this remain a CLR type for clarity?
/// </summary>
public class DisplayHelper {
public class DisplayHelper : DynamicObject {
private readonly IDisplayManager _displayManager;
private readonly IShapeFactory _shapeFactory;
@ -29,6 +24,16 @@ namespace Orchard.DisplayManagement.Implementation {
public ViewContext ViewContext { get; set; }
public IViewDataContainer ViewDataContainer { get; set; }
public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) {
result = Invoke(null, Arguments.From(args, binder.CallInfo.ArgumentNames));
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) {
result = Invoke(binder.Name, Arguments.From(args, binder.CallInfo.ArgumentNames));
return true;
}
public object Invoke(string name, INamedEnumerable<object> parameters) {
if (!string.IsNullOrEmpty(name)) {
return ShapeTypeExecute(name, parameters);
@ -67,6 +72,10 @@ namespace Orchard.DisplayManagement.Implementation {
}
public object ShapeExecute(object shape) {
if (shape == null) {
return new HtmlString(string.Empty);
}
var context = new DisplayContext { Display = this, Value = shape, ViewContext = ViewContext, ViewDataContainer = ViewDataContainer };
return _displayManager.Execute(context);
}

View File

@ -1,10 +1,7 @@
using System;
using System.Web.Mvc;
using ClaySharp;
using System.Web.Mvc;
namespace Orchard.DisplayManagement.Implementation {
public class DisplayHelperFactory : IDisplayHelperFactory {
static private readonly DisplayHelperBehavior[] _behaviors = new[] { new DisplayHelperBehavior() };
private readonly IDisplayManager _displayManager;
private readonly IShapeFactory _shapeFactory;
@ -14,20 +11,11 @@ namespace Orchard.DisplayManagement.Implementation {
}
public dynamic CreateHelper(ViewContext viewContext, IViewDataContainer viewDataContainer) {
return ClayActivator.CreateInstance<DisplayHelper>(
_behaviors,
return new DisplayHelper(
_displayManager,
_shapeFactory,
viewContext,
viewDataContainer);
}
class DisplayHelperBehavior : ClayBehavior {
public override object InvokeMember(Func<object> proceed, object target, string name, INamedEnumerable<object> args) {
return ((DisplayHelper)target).Invoke(name, args);
}
}
}
}

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using ClaySharp;
namespace Orchard.DisplayManagement.Implementation {
public interface IShapeFactoryEvents : IDependency {
@ -12,8 +11,7 @@ namespace Orchard.DisplayManagement.Implementation {
public IShapeFactory ShapeFactory { get; set; }
public dynamic New { get; set; }
public string ShapeType { get; set; }
public Type BaseType { get; set; }
public IList<IClayBehavior> Behaviors { get; set; }
public Func<dynamic> Create { get; set; }
public IList<Action<ShapeCreatedContext>> OnCreated { get; set; }
}

View File

@ -0,0 +1,137 @@
using System.Collections;
using System.Collections.Specialized;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
namespace Orchard.DisplayManagement.Shapes {
public class Composite : DynamicObject {
private readonly IDictionary _props = new HybridDictionary();
public override bool TryGetMember(GetMemberBinder binder, out object result) {
return TryGetMemberImpl(binder.Name, out result);
}
protected bool TryGetMemberImpl(string name, out object result) {
if (_props.Contains(name)) {
result = _props[name];
return true;
}
result = null;
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value) {
return TrySetMemberImpl(binder.Name, value);
}
protected bool TrySetMemberImpl(string name, object value) {
_props[name] = value;
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) {
if (!args.Any()) {
return TryGetMemberImpl(binder.Name, out result);
}
// method call with one argument will assign the property
if (args.Count() == 1) {
result = this;
return TrySetMemberImpl(binder.Name, args.Single());
}
if (!base.TryInvokeMember(binder, args, out result)) {
if (binder.Name == "ToString") {
result = string.Empty;
return true;
}
return false;
}
return true;
}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) {
if (indexes.Count() != 1) {
return base.TryGetIndex(binder, indexes, out result);
}
var index = indexes.Single();
if (_props.Contains(index)) {
result = _props[index];
return true;
}
// try to access an existing member
var strinIndex = index as string;
if (strinIndex != null && TryGetMemberImpl(strinIndex, out result)) {
return true;
}
return base.TryGetIndex(binder, indexes, out result);
}
public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) {
if (indexes.Count() != 1) {
return base.TrySetIndex(binder, indexes, value);
}
var index = indexes.Single();
// try to access an existing member
var strinIndex = index as string;
if (strinIndex != null && TrySetMemberImpl(strinIndex, value)) {
return true;
}
_props[indexes.Single()] = value;
return true;
}
public IDictionary Properties {
get { return _props; }
}
}
public class Nil : DynamicObject {
static readonly object Singleton = new Nil();
public static object Instance { get { return Singleton; } }
private Nil() {
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
result = Instance;
return true;
}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) {
result = Instance;
return true;
}
public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result) {
switch (binder.Operation) {
case ExpressionType.Equal:
result = ReferenceEquals(arg, Nil.Instance) || arg == null;
return true;
case ExpressionType.NotEqual:
result = !ReferenceEquals(arg, Nil.Instance) && arg != null;
return true;
}
return base.TryBinaryOperation(binder, arg, out result);
}
public override bool TryConvert(ConvertBinder binder, out object result) {
result = null;
return true;
}
}
}

View File

@ -1,28 +1,31 @@
using System;
using System.Diagnostics;
using System.Dynamic;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Web.Mvc;
using ClaySharp;
using ClaySharp.Implementation;
namespace Orchard.DisplayManagement.Shapes {
[DebuggerTypeProxy(typeof(ShapeDebugView))]
public class Shape : IShape, IEnumerable {
public class Shape : Composite, IShape, IEnumerable<object> {
private const string DefaultPosition = "5";
private readonly IList<object> _items = new List<object>();
private readonly IList<string> _classes = new List<string>();
private readonly IDictionary<string, string> _attributes = new Dictionary<string, string>();
public virtual ShapeMetadata Metadata { get; set; }
public ShapeMetadata Metadata { get; set; }
public virtual string Id { get; set; }
public virtual IList<string> Classes { get { return _classes; } }
public virtual IDictionary<string, string> Attributes { get { return _attributes; } }
public virtual IEnumerable<dynamic> Items { get { return _items; } }
public Shape() {
Metadata = new ShapeMetadata();
}
public virtual Shape Add(object item, string position = null) {
// pszmyd: Ignoring null shapes
if (item == null) {
@ -31,12 +34,12 @@ namespace Orchard.DisplayManagement.Shapes {
try {
// todo: (sebros) this is a temporary implementation to prevent common known scenarios throwing exceptions. The final solution would need to filter based on the fact that it is a Shape instance
if ( item is MvcHtmlString ||
item is String ) {
if (item is MvcHtmlString ||
item is String) {
// need to implement positioned wrapper for non-shape objects
}
else if (item is IShape) {
((dynamic) item).Metadata.Position = position;
((dynamic)item).Metadata.Position = position;
}
}
catch {
@ -53,126 +56,144 @@ namespace Orchard.DisplayManagement.Shapes {
return this;
}
IEnumerator<object> IEnumerable<object>.GetEnumerator() {
return _items.GetEnumerator();
}
public virtual IEnumerator GetEnumerator() {
return _items.GetEnumerator();
}
public class ShapeBehavior : ClayBehavior {
public override object SetIndex(Func<object> proceed, dynamic self, IEnumerable<object> keys, object value) {
if (keys.Count() == 1) {
var name = keys.Single().ToString();
if (name.Equals("Id")) {
// need to mutate the actual type
var s = self as Shape;
if (s != null) {
s.Id = System.Convert.ToString(value);
}
return value;
}
if (name.Equals("Classes")) {
var args = Arguments.From(new[] { value }, Enumerable.Empty<string>());
MergeClasses(args, self.Classes);
return value;
}
if (name.Equals("Attributes")) {
var args = Arguments.From(new[] { value }, Enumerable.Empty<string>());
MergeAttributes(args, self.Attributes);
return value;
}
if (name.Equals("Items")) {
var args = Arguments.From(new[] { value }, Enumerable.Empty<string>());
MergeItems(args, self);
return value;
}
}
return proceed();
public override bool TryConvert(ConvertBinder binder, out object result) {
result = Items;
if (binder.ReturnType == typeof(IEnumerable<object>)
|| binder.ReturnType == typeof(IEnumerable<dynamic>)) {
return true;
}
public override object InvokeMember(Func<object> proceed, dynamic self, string name, INamedEnumerable<object> args) {
return false;
}
//public class ShapeBehavior : ClayBehavior {
public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) {
if (indexes.Count() == 1) {
var name = indexes.Single().ToString();
if (name.Equals("Id")) {
// need to mutate the actual type
var s = self as Shape;
if (s != null) {
s.Id = System.Convert.ToString(args.FirstOrDefault());
}
return self;
Id = Convert.ToString(value);
return true;
}
if (name.Equals("Classes") && !args.Named.Any()) {
MergeClasses(args, self.Classes);
return self;
if (name.Equals("Classes")) {
var args = Arguments.From(new[] { value }, Enumerable.Empty<string>());
MergeClasses(args, Classes);
return true;
}
if (name.Equals("Attributes") && args.Positional.Count() <= 1) {
MergeAttributes(args, self.Attributes);
return self;
if (name.Equals("Attributes")) {
var args = Arguments.From(new[] { value }, Enumerable.Empty<string>());
MergeAttributes(args, Attributes);
return true;
}
if (name.Equals("Items")) {
MergeItems(args, self);
return self;
}
return proceed();
}
private static void MergeAttributes(INamedEnumerable<object> args, IDictionary<string, string> attributes) {
var arg = args.Positional.SingleOrDefault();
if (arg != null) {
if (arg is IDictionary) {
var dictionary = arg as IDictionary;
foreach (var key in dictionary.Keys) {
attributes[System.Convert.ToString(key)] = System.Convert.ToString(dictionary[key]);
}
}
else {
foreach (var prop in arg.GetType().GetProperties()) {
attributes[TranslateIdentifier(prop.Name)] = System.Convert.ToString(prop.GetValue(arg, null));
}
}
}
foreach (var named in args.Named) {
attributes[named.Key] = System.Convert.ToString(named.Value);
var args = Arguments.From(new[] { value }, Enumerable.Empty<string>());
MergeItems(args, this);
return true;
}
}
private static string TranslateIdentifier(string name) {
// Allows for certain characters in an identifier to represent different
// characters in an HTML attribute (mimics MVC behavior):
// data_foo ==> data-foo
// @keyword ==> keyword
return name.Replace("_", "-").Replace("@", "");
return base.TrySetIndex(binder, indexes, value);
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) {
var name = binder.Name;
var arguments = Arguments.From(args, binder.CallInfo.ArgumentNames);
if (name.Equals("Id")) {
// need to mutate the actual type
Id = Convert.ToString(args.FirstOrDefault());
result = this;
return true;
}
if (name.Equals("Classes") && !arguments.Named.Any()) {
MergeClasses(arguments, Classes);
result = this;
return true;
}
if (name.Equals("Attributes") && arguments.Positional.Count() <= 1) {
MergeAttributes(arguments, Attributes);
result = this;
return true;
}
if (name.Equals("Items")) {
MergeItems(arguments, this);
result = this;
return true;
}
private static void MergeClasses(INamedEnumerable<object> args, IList<string> classes) {
foreach (var arg in args) {
// look for string first, because the "string" type is also an IEnumerable of char
if (arg is string) {
classes.Add(arg as string);
return base.TryInvokeMember(binder, args, out result);
}
private static void MergeAttributes(INamedEnumerable<object> args, IDictionary<string, string> attributes) {
var arg = args.Positional.SingleOrDefault();
if (arg != null) {
if (arg is IDictionary) {
var dictionary = arg as IDictionary;
foreach (var key in dictionary.Keys) {
attributes[Convert.ToString(key)] = Convert.ToString(dictionary[key]);
}
else if (arg is IEnumerable) {
foreach (var item in arg as IEnumerable) {
classes.Add(System.Convert.ToString(item));
}
}
else {
classes.Add(System.Convert.ToString(arg));
}
else {
foreach (var prop in arg.GetType().GetProperties()) {
attributes[TranslateIdentifier(prop.Name)] = Convert.ToString(prop.GetValue(arg, null));
}
}
}
foreach (var named in args.Named) {
attributes[named.Key] = Convert.ToString(named.Value);
}
}
private static void MergeItems(INamedEnumerable<object> args, dynamic shape) {
foreach (var arg in args) {
// look for string first, because the "string" type is also an IEnumerable of char
if (arg is string) {
shape.Add(arg as string);
}
else if (arg is IEnumerable) {
foreach (var item in arg as IEnumerable) {
shape.Add(item);
}
}
else {
shape.Add(System.Convert.ToString(arg));
private static string TranslateIdentifier(string name) {
// Allows for certain characters in an identifier to represent different
// characters in an HTML attribute (mimics MVC behavior):
// data_foo ==> data-foo
// @keyword ==> keyword
return name.Replace("_", "-").Replace("@", "");
}
private static void MergeClasses(INamedEnumerable<object> args, IList<string> classes) {
foreach (var arg in args) {
// look for string first, because the "string" type is also an IEnumerable of char
if (arg is string) {
classes.Add(arg as string);
}
else if (arg is IEnumerable) {
foreach (var item in arg as IEnumerable) {
classes.Add(Convert.ToString(item));
}
}
else {
classes.Add(Convert.ToString(arg));
}
}
}
private static void MergeItems(INamedEnumerable<object> args, dynamic shape) {
foreach (var arg in args) {
// look for string first, because the "string" type is also an IEnumerable of char
if (arg is string) {
shape.Add(arg as string);
}
else if (arg is IEnumerable) {
foreach (var item in arg as IEnumerable) {
shape.Add(item);
}
}
else {
shape.Add(Convert.ToString(arg));
}
}
}
}
}

View File

@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ClaySharp;
namespace Orchard.DisplayManagement.Shapes {
public class ShapeDebugView {
@ -19,12 +19,12 @@ namespace Orchard.DisplayManagement.Shapes {
public IEnumerable<dynamic> Items { get { return _shape.Items; } }
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePairs[] ClayProperties {
public KeyValuePairs[] Properties {
get {
var members = new Dictionary<string, object>();
((IClayBehaviorProvider)_shape).Behavior.GetMembers(() => null, _shape, members);
return members.Keys.Select(key => new KeyValuePairs(key, members[key])).ToArray();
return _shape.Properties
.Cast<DictionaryEntry>()
.Select(entry => new KeyValuePairs(entry.Key, entry.Value))
.ToArray();
}
}
@ -32,20 +32,11 @@ namespace Orchard.DisplayManagement.Shapes {
public class KeyValuePairs {
public KeyValuePairs(object key, object value) {
try {
var dynProxyGetTarget = value.GetType().GetMethod("DynProxyGetTarget");
if (dynProxyGetTarget != null) {
_value = dynProxyGetTarget.Invoke(value, null);
_shapeType = ((IShape)_value).Metadata.Type;
}
else {
_value = value;
}
}
catch {
_value = value;
if (_value is IShape) {
_shapeType = ((IShape)_value).Metadata.Type;
}
_value = value;
_key = key;
}

View File

@ -71,11 +71,6 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\Castle Windsor 2.0\bin\Castle.DynamicProxy2.dll</HintPath>
</Reference>
<Reference Include="ClaySharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\claysharp\ClaySharp.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="FluentNHibernate, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8aa435e3cb308880, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\nhibernate\FluentNHibernate.dll</HintPath>
@ -157,8 +152,6 @@
<Compile Include="ContentManagement\Aspects\ITitleAspect.cs" />
<Compile Include="ContentManagement\Aspects\ILocalizableAspect.cs" />
<Compile Include="ContentManagement\ContentIdentity.cs" />
<Compile Include="ContentManagement\ContentItemBehavior.cs" />
<Compile Include="ContentManagement\ContentPartBehavior.cs" />
<Compile Include="ContentManagement\DefaultHqlQuery.cs" />
<Compile Include="ContentManagement\Handlers\UpdateContentContext.cs" />
<Compile Include="ContentManagement\IHqlExpression.cs" />
@ -172,12 +165,11 @@
<Compile Include="ContentManagement\Handlers\BuildShapeContext.cs" />
<Compile Include="ContentManagement\Handlers\ExportContentContext.cs" />
<Compile Include="ContentManagement\Handlers\ImportContentContext.cs" />
<Compile Include="ContentManagement\IContentBehavior.cs" />
<Compile Include="ContentManagement\ImportContentSession.cs" />
<Compile Include="ContentManagement\MetaData\Services\ISettingsFormatter.cs" />
<Compile Include="ContentManagement\QueryHints.cs" />
<Compile Include="ContentManagement\Utilities\ComputedField.cs" />
<Compile Include="Data\Bags\SArray.cs" />
<Compile Include="DisplayManagement\Arguments.cs" />
<Compile Include="Data\Bags\SConvert.cs" />
<Compile Include="Data\Bags\Serialization\IBagSerializer.cs" />
<Compile Include="Data\Bags\Serialization\XmlSettingsSerializer.cs" />
@ -204,6 +196,8 @@
<Compile Include="DisplayManagement\Descriptors\ShapeTableLocator.cs" />
<Compile Include="DisplayManagement\Implementation\IShapeDisplayEvents.cs" />
<Compile Include="DisplayManagement\Implementation\IShapeFactoryEvents.cs" />
<Compile Include="DisplayManagement\INamedEnumerable.cs" />
<Compile Include="DisplayManagement\Shapes\Composite.cs" />
<Compile Include="DisplayManagement\Shapes\ShapeDebugView.cs" />
<Compile Include="DisplayManagement\Shapes\ITagBuilderFactory.cs" />
<Compile Include="Environment\CollectionOrderModule.cs" />

View File

@ -1,5 +1,4 @@
using System;
using ClaySharp.Implementation;
using Orchard.DisplayManagement;
namespace Orchard.UI.Zones {

View File

@ -1,7 +1,7 @@
using System;
using System.Linq;
using ClaySharp;
using ClaySharp.Behaviors;
using System.Linq.Expressions;
using Orchard.DisplayManagement.Shapes;
namespace Orchard.UI.Zones {
/// <summary>
@ -17,102 +17,179 @@ namespace Orchard.UI.Zones {
/// Foo.Alpha :same
///
/// </summary>
public class ZoneHoldingBehavior : ClayBehavior {
public class ZoneHolding : Shape {
private readonly Func<dynamic> _zoneFactory;
private readonly dynamic _layoutShape;
public ZoneHoldingBehavior(Func<dynamic> zoneFactory, dynamic layoutShape) {
public ZoneHolding(Func<dynamic> zoneFactory) {
_zoneFactory = zoneFactory;
_layoutShape = layoutShape;
}
public override object GetMember(Func<object> proceed, object self, string name) {
if (name == "Zones") {
// provide a robot for zone manipulation on parent object
return ClayActivator.CreateInstance(new IClayBehavior[] {
new InterfaceProxyBehavior(),
new ZonesBehavior(_zoneFactory, self, _layoutShape)
});
private Zones _zones;
public Zones Zones {
get {
if (_zones == null) {
return _zones = new Zones(_zoneFactory, this);
}
return _zones;
}
}
var result = proceed();
if (((dynamic)result) == null) {
public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result) {
var name = binder.Name;
if (!base.TryGetMember(binder, out result) || ((dynamic)result) == null) {
// substitute nil results with a robot that turns adds a zone on
// the parent when .Add is invoked
return ClayActivator.CreateInstance(new IClayBehavior[] {
new InterfaceProxyBehavior(),
new NilBehavior(),
new ZoneOnDemandBehavior(_zoneFactory, self, name)
});
result = new ZoneOnDemand(_zoneFactory, this, name);
TrySetMemberImpl(name, result);
}
return result;
return true;
}
public class ZonesBehavior : ClayBehavior {
private readonly Func<dynamic> _zoneFactory;
private object _parent;
private readonly dynamic _layoutShape;
}
public ZonesBehavior(Func<dynamic> zoneFactory, object parent, dynamic layoutShape) {
_zoneFactory = zoneFactory;
_parent = parent;
_layoutShape = layoutShape;
/// <remarks>
/// InterfaceProxyBehavior()
/// ZonesBehavior(_zoneFactory, self, _layoutShape) => Create ZoneOnDemand if member access
/// </remarks>
public class Zones : Composite {
private readonly Func<dynamic> _zoneFactory;
private readonly object _parent;
public Zones(Func<dynamic> zoneFactory, object parent) {
_zoneFactory = zoneFactory;
_parent = parent;
}
public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result) {
return TryGetMemberImpl(binder.Name, out result);
}
private bool TryGetMemberImpl(string name, out object result) {
var parentMember = ((dynamic)_parent)[name];
if (parentMember == null) {
result = new ZoneOnDemand(_zoneFactory, _parent, name);
return true;
}
public override object GetMember(Func<object> proceed, object self, string name) {
var parentMember = ((dynamic)_parent)[name];
if (parentMember == null) {
return ClayActivator.CreateInstance(new IClayBehavior[] {
new InterfaceProxyBehavior(),
new NilBehavior(),
new ZoneOnDemandBehavior(_zoneFactory, _parent, name)
});
}
return parentMember;
}
public override object GetIndex(Func<object> proceed, object self, System.Collections.Generic.IEnumerable<object> keys) {
if (keys.Count() == 1) {
var key = System.Convert.ToString(keys.Single());
result = parentMember;
return true;
}
return GetMember(proceed, null, key);
}
return proceed();
public override bool TryGetIndex(System.Dynamic.GetIndexBinder binder, object[] indexes, out object result) {
if (indexes.Count() == 1) {
var key = Convert.ToString(indexes.Single());
return TryGetMemberImpl(key, out result);
}
return base.TryGetIndex(binder, indexes, out result);
}
}
/// <remarks>
/// InterfaceProxyBehavior()
/// NilBehavior() => return Nil on GetMember and GetIndex in all cases
/// ZoneOnDemandBehavior(_zoneFactory, _parent, name) => when a zone (Shape) is
/// created, replace itself with the zone so that Layout.ZoneName is no more equal to Nil
/// </remarks>
public class ZoneOnDemand : Shape {
private readonly Func<dynamic> _zoneFactory;
private readonly object _parent;
private readonly string _potentialZoneName;
public ZoneOnDemand(Func<dynamic> zoneFactory, object parent, string potentialZoneName) {
_zoneFactory = zoneFactory;
_parent = parent;
_potentialZoneName = potentialZoneName;
}
public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result) {
// NilBehavior
result = Nil.Instance;
return true;
}
public override bool TryGetIndex(System.Dynamic.GetIndexBinder binder, object[] indexes, out object result) {
// NilBehavior
result = Nil.Instance;
return true;
}
public override bool TryInvokeMember(System.Dynamic.InvokeMemberBinder binder, object[] args, out object result) {
var name = binder.Name;
// NilBehavior
if (!args.Any() && name != "ToString") {
result = Nil.Instance;
return true;
}
return base.TryInvokeMember(binder, args, out result);
}
public override string ToString() {
return String.Empty;
}
public override bool TryConvert(System.Dynamic.ConvertBinder binder, out object result) {
result = null;
return true;
}
public static bool operator ==(ZoneOnDemand expr, object arg) {
// if ZoneOnDemand is compared to null it must return true
return arg == null || ReferenceEquals(arg, Nil.Instance);
}
public static bool operator !=(ZoneOnDemand expr, object arg) {
// if ZoneOnDemand is compared to null it must return true
return arg != null && !ReferenceEquals(arg, Nil.Instance);
}
public override bool Equals(object obj) {
if (ReferenceEquals(null, obj)) {
return true;
}
if (ReferenceEquals(this, obj)) {
return true;
}
return false;
}
public override int GetHashCode() {
unchecked {
int hashCode = (_parent != null ? _parent.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (_potentialZoneName != null ? _potentialZoneName.GetHashCode() : 0);
return hashCode;
}
}
public class ZoneOnDemandBehavior : ClayBehavior {
private readonly Func<dynamic> _zoneFactory;
private readonly object _parent;
private readonly string _potentialZoneName;
public ZoneOnDemandBehavior(Func<dynamic> zoneFactory, object parent, string potentialZoneName) {
_zoneFactory = zoneFactory;
_parent = parent;
_potentialZoneName = potentialZoneName;
}
public override object InvokeMember(Func<object> proceed, object self, string name, INamedEnumerable<object> args) {
var argsCount = args.Count();
if (name == "Add" && (argsCount == 1 || argsCount == 2)) {
// pszmyd: Ignore null shapes
if (args.First() == null)
return _parent;
dynamic parent = _parent;
dynamic zone = _zoneFactory();
zone.Parent = _parent;
zone.ZoneName = _potentialZoneName;
parent[_potentialZoneName] = zone;
if (argsCount == 1)
return zone.Add(args.Single());
return zone.Add(args.First(), (string)args.Last());
public override Shape Add(object item, string position = null) {
if (item == null) {
return (Shape)_parent;
}
return proceed();
}
dynamic parent = _parent;
dynamic zone = _zoneFactory();
zone.Parent = _parent;
zone.ZoneName = _potentialZoneName;
parent[_potentialZoneName] = zone;
if (position == null) {
return zone.Add(item);
}
return zone.Add(item, position);
}
}
}

View File

@ -41,7 +41,7 @@ namespace Orchard {
/// The Layout shape corresponding to the work context
/// </summary>
public dynamic Layout {
get { return GetState<object>("Layout"); }
get { return GetState<dynamic>("Layout"); }
set { SetState("Layout", value); }
}